diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-02-02 12:42:10 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-02-02 12:42:10 -0800 |
commit | 8910f1cd79445bbe2da01f8ccf7c37909349529e (patch) | |
tree | ba67a346969358fd7cc2b7c12384479de8364cab /gcc/cp | |
parent | 45c32be1f96ace25b66c34a84818dc5e07e9d516 (diff) | |
parent | 8e4a738d2540ab6aff77506d368bf4e3fa6963bd (diff) | |
download | gcc-8910f1cd79445bbe2da01f8ccf7c37909349529e.zip gcc-8910f1cd79445bbe2da01f8ccf7c37909349529e.tar.gz gcc-8910f1cd79445bbe2da01f8ccf7c37909349529e.tar.bz2 |
Merge from trunk revision 8e4a738d2540ab6aff77506d368bf4e3fa6963bd.
Diffstat (limited to 'gcc/cp')
58 files changed, 32237 insertions, 6867 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f0386a1..bac41f1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6026 +1,466 @@ -2020-12-05 Patrick Palka <ppalka@redhat.com> +2021-02-01 Patrick Palka <ppalka@redhat.com> - PR c++/97093 - * constraint.cc (parameter_mapping_equivalent_p): Add some - sanity checks. Clarify comment. - (tsubst_nested_requirement): Always perform satisfaction - quietly first. If that yields an erroneous result, emit a - context message and replay satisfaction noisily with the - diagnostic normal form. - (finish_nested_requirement): Normalize the constraint-expression - twice, once with diagnostic information and once without. Store - them in a TREE_LIST within the TREE_TYPE. - (diagnose_nested_requirement): When replaying satisfaction, use - the diagnostic normal form instead of renormalizing on the spot. + PR c++/98295 + * constexpr.c (cxx_eval_array_reference): Also set + new_ctx.object when setting new_ctx.ctor. -2020-12-05 Patrick Palka <ppalka@redhat.com> +2021-02-01 Marek Polacek <polacek@redhat.com> - PR c++/97093 - * constraint.cc (struct sat_info): Define. - (tsubst_nested_requirement): Pass a sat_info object to - satisfy_constraint. - (satisfy_constraint_r): Take a sat_info argument instead of - subst_info. - (satisfy_conjunction): Likewise. - (satisfy_disjunction): Likewise. Instead of first evaluating - each branch quietly, evaluate each branch only with - unsatisfaction diagnostics disabled. Exit early if evaluation - of a branch returns error_mark_node. - (satisfy_atom): Take a sat_info argument instead of subst_info. - Fix a comment. Check diagnose_unsatisfaction_p() instead of - noisy() before replaying a substitution failure. - (satisfy_constraint): Take a sat_info argument instead of - subst_info. - (satisfy_associated_constraints): Likewise. - (satisfy_constraint_expression): Likewise. - (satisfy_declaration_constraints): Likewise. - (constraint_satisfaction_value): Likewise and adjust - accordingly. Fix formatting. - (constraints_satisfied_p): Pass a sat_info object to - constraint_satisfaction_value. - (evaluate_concept_check): Pass a sat_info object to - satisfy_constraint_expression. - (diagnose_nested_requirement): Likewise. - (diagnose_constraints): Pass an appropriate sat_info object to - constraint_satisfaction_value. + PR c++/98355 + * parser.c (cp_parser_has_attribute_expression): Use + uses_template_parms instead of type_dependent_expression_p. -2020-12-05 Jakub Jelinek <jakub@redhat.com> +2021-02-01 Jason Merrill <jason@redhat.com> - PR c++/98122 - * constexpr.c (cxx_union_active_member): New function. - (cxx_fold_indirect_ref_1): Add ctx argument, pass it through to - recursive call. Handle UNION_TYPE. - (cxx_fold_indirect_ref): Add ctx argument, pass it to recursive calls - and cxx_fold_indirect_ref_1. - (cxx_eval_indirect_ref): Adjust cxx_fold_indirect_ref calls. - -2020-12-04 Jason Merrill <jason@redhat.com> - - PR c++/93083 - * pt.c (convert_template_argument): Handle equivalent placeholders. - (do_class_deduction): Look through EXPR_PACK_EXPANSION, too. - -2020-12-04 Jason Merrill <jason@redhat.com> - - * decl2.c (clear_consteval_vfns): Remove *. - * pt.c (do_auto_deduction): Remove *. - * parser.c (cp_parser_late_parsing_default_args): Change loop - to use range 'for'. - -2020-12-04 Nathan Sidwell <nathan@acm.org> - - PR c++/98116 - * cp-tree.h (comparing_typenames): Delete. - (cplus_build_array_type): Remove default parm. - * pt.c (comparing_typenames): Delete. - (spec_hasher::equal): Don't increment it. - * tree.c (set_array_type_canon): Remove dep parm. - (build_cplus_array_type): Remove dep parm changes. - (cp_build_qualified_type_real): Remove dependent array type - changes. - (strip_typedefs): Likewise. - * typeck.c (structural_comptypes): Revert comparing_typename - changes. - -2020-12-04 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h: Add various inline module state predicates, and - declare the API that will be provided by modules.cc - -2020-12-04 Jakub Jelinek <jakub@redhat.com> - - PR c++/80780 - * cp-gimplify.c (fold_builtin_source_location): Use 2 instead of 0 - as last argument to cxx_printable_name. - -2020-12-03 Jason Merrill <jason@redhat.com> - - * cp-tree.h (releasing_vec::operator[]): Change parameter type to - ptrdiff_t. - -2020-12-03 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (OVL_EXPORT): New. - (class ovl_iterator): Add get_using, exporting_p. - * tree.c (ovl_insert): Extend using_or_hidden meaning to include - an exported using. - -2020-12-03 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (DECL_UNINSTANTIATED_TEMPLATE_FRIEND): New. - * pt.c (push_template_decl): Set it. - (tsubst_friend_function): Clear it. - -2020-12-03 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (make_unbound_class_template_raw): Declare. - (canonical_type_parameter): Declare. - * decl.c (make_unbound_class_template_raw): Break out of ... - (make_unboud_class_template): ... here. Call it. - * pt.c (canonical_type_parameter): Externalize. Refactor & set - structural_equality for type parms. - -2020-12-03 Nathan Sidwell <nathan@acm.org> - - PR c++/98107 - * tree.c (build_cplus_array_type): Mark dependency of new variant. - (cp_build_qualified_type_real, strip_typedefs): Assert - TYPE_DEPENDENT_P_VALID, or not a dependent type. - -2020-12-03 Jakub Jelinek <jakub@redhat.com> - - PR libstdc++/93121 - * cp-tree.h (cp_build_bit_cast): Declare. - * cp-tree.def (BIT_CAST_EXPR): New tree code. - * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_BIT_CAST. - (cp_common_init_ts): Handle BIT_CAST_EXPR. - * cxx-pretty-print.c (cxx_pretty_printer::postfix_expression): - Likewise. - * parser.c (cp_parser_postfix_expression): Handle - RID_BUILTIN_BIT_CAST. - * semantics.c (cp_build_bit_cast): New function. - * tree.c (cp_tree_equal): Handle BIT_CAST_EXPR. - (cp_walk_subtrees): Likewise. - * pt.c (tsubst_copy): Likewise. - * constexpr.c (check_bit_cast_type, cxx_eval_bit_cast): New functions. - (cxx_eval_constant_expression): Handle BIT_CAST_EXPR. - (potential_constant_expression_1): Likewise. - * cp-gimplify.c (cp_genericize_r): Likewise. - -2020-12-03 Jason Merrill <jason@redhat.com> - - * parser.c (cp_parser_primary_expression): Distinguish - parms from vars in error. - (cp_parser_late_parsing_default_args): Pushdecl parms - as we go. - -2020-12-03 Jason Merrill <jason@redhat.com> - - * name-lookup.c (begin_scope): Set immediate_fn_ctx_p. - * parser.c (cp_parser_late_parsing_default_args): Push - sk_function_parms scope. - -2020-12-03 Peter Bergner <bergner@linux.ibm.com> - - PR c++/97947 - * typeck2.c (digest_init_r): Handle OPAQUE_TYPE as an aggregate type. - -2020-12-02 Jakub Jelinek <jakub@redhat.com> - - PR c++/80780 - PR c++/93093 - * cp-tree.h (source_location_current_p): Declare. - * tree.c (source_location_current_p): New function. - * call.c (immediate_invocation_p): New function. - (build_over_call): Use it to resolve LWG3396. - * constexpr.c (cxx_eval_builtin_function_call): Temporarily set - current_function_decl from ctx->call->fundef->decl if any. - * cp-gimplify.c (cp_genericize_r) <case CALL_EXPR>: Fold calls - to immediate function std::source_location::current (). - -2020-12-02 Jason Merrill <jason@redhat.com> - - * decl.c (grokdeclarator): Improve diagnostic for - disallowed CTAD placeholder. - -2020-12-02 Jason Merrill <jason@redhat.com> - - * decl.c (check_initializer): Also look through STMT_EXPR - and BIND_EXPR. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (comparing_typenames): Declare. - * pt.c (comparing_typenames): Define. - (spec_hasher::equal): Increment it around comparisons. - * typeck.c (structural_comptypes): Adjust TYPENAME resolution - check. - -2020-12-02 Marek Polacek <polacek@redhat.com> - - PR c++/97975 - * constexpr.c (fold_non_dependent_init): Add a tree parameter. - Use it. - * cp-tree.h (fold_non_dependent_init): Add a tree parameter with - a default value. - * typeck2.c (store_init_value): Call fold_non_dependent_expr - only when checking the initializer for constexpr variables. - Call fold_non_dependent_init instead of maybe_constant_init. - -2020-12-02 Marek Polacek <polacek@redhat.com> - - PR c++/97187 - PR c++/97993 - * pt.c (tsubst_copy_and_build) <case NEW_EXPR>: Return error_mark_node - if init is erroneous. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (DECL_MODULE_PURVIEW_P, DECL_MODULE_IMPORT_P) - (DECL_MODULE_ENTITY_P): New. - (DECL_MODULE_PENDING_SPECIALIZATIONS_P): New. - (DECL_MODULE_PENDING_MEMBERS_P): New. - (DECL_MODULE_ATTACHMENTS_P): New. - (DECL_MODULE_EXPORT_P): New. - (struct lang_decl_base): Shrink sel field. Add new - module-specific fields. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (DECL_TINFO_P): Also for TYPE_DECLs. - (get_tinfo_decl_direct): Declare. - (get_pseudo_tinfo_index, get_pseudo_tinfo_type): Declare. - * rtti.c (get_tinfo_decl_direct): Externalize. - (get_tinfo_desc): Set DECL_TINFO_P on the typedef. - (get_pseudo_tinfo_index, get_pseudo_tinfo_type): New. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (maybe_add_lang_decl_raw, maybe_add_lang_type_raw): - Declare. - * lex.c (maybe_add_lang_decl_raw, maybe_add_lang_type_raw): - Externalize, reformat. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (build_cplus_array_type): Add defaulted DEP parm. - * tree.c (set_array_type_common): Add DEP parm. - (build_cplus_array_type): Add DEP parm, determine dependency if - needed. - (cp_build_qualified_type_real): Adjust array-building call. - (strip_typedefs): Likewise. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * ptree.c (cxx_print_xnode): Increase binding-vector prefix size. - -2020-12-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.def (BINDING_VECTOR): New. - * name-lookup.h (struct binding_slot): New. - (BINDING_VECTOR_SLOTS_PER_CLUSTER): New. - (struct binding_index, struct binding_cluster): New. - (BINDING_VECTOR_ALLOC_CLUSTERS, BINDING_VECTOR_CLUSTER_BASE) - (BINDING_VECTOR_CLUSTER): New. - (struct tree_binding_vec): New. - (BINDING_VECTOR_NAME, BINDING_VECTOR_GLOBAL_DUPS_P) - (BINDING_VECTOR_PARTITION_DUPS_P): New. - (BINDING_BINDING_GLOBAL_P, BINDING_BINDING_PARTITION_P): New. - (BINDING_VECTOR_PENDING_SPECIALIZATIONS) - (BINDING_VECTOR_PENDING_IS_HEADER_P) - (BINDING_VECTOR_PENDING_IS_PARTITION_P): New. - * cp-tree.h (enum cp_tree_node_structure_enum): Add - TS_CP_BINDING_VECTOR. - (union lang_tree_node): Add binding_vec field. - (make_binding_vec): Declare. - (named_decl_hash::hash, named_decl_hash::equal): Check for binding - vector. - * decl.c (cp_tree_node_structure): Add BINDING_VECTOR case. - * ptree.c (cxx_print_xnode): Add BINDING_VECTOR case. - * tree.c (make_binding_vec): New. - -2020-12-01 Ville Voutilainen <ville.voutilainen@gmail.com> - - PR c++/98054 - * cxx-pretty-print.c (pp_cxx_trait_expression): - Add support for __is_nothrow_{assignable,constructible}. - -2020-12-01 Jakub Jelinek <jakub@redhat.com> - - PR c++/98072 - * parser.c (cp_parser_omp_depobj): Suppress location wrappers when - parsing depend clause. - -2020-12-01 Nathan Sidwell <nathan@acm.org> - - * lex.c (init_reswords): Maybe enable module keywords. - -2020-12-01 Nathan Sidwell <nathan@acm.org> - - * lang-specs.h: Add module-related options. - -2020-12-01 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_declaration): Add a not about where - attributes may be placed. - -2020-11-27 Martin Sebor <msebor@redhat.com> - - * error.c (add_quotes): Revert previous change and use pragma to - suppress -Wformat-diag. - -2020-11-26 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> - - * g++spec.c (TIMELIB, TIME_LIBRARY): Remove. - (lang_specific_driver): Remove TIME_LIBRARY handling. - -2020-11-26 Thomas Schwinge <thomas@codesourcery.com> - - * parser.c (cp_parser_omp_var_list_no_open): Assert that array - section's 'low_bound', 'length' are not location wrapper nodes. - (cp_parser_oacc_all_clauses, cp_parser_oacc_cache): Instantiate - 'auto_suppress_location_wrappers'. - -2020-11-25 Martin Sebor <msebor@redhat.com> - - PR bootstrap/94982 - * constraint.cc (debug_argument_list): Avoid -Wformat-diag. - * error.c (function_category): Same. - (print_template_differences): Same. - * logic.cc (debug): Same. - * name-lookup.c (lookup_using_decl): Same. - * parser.c (maybe_add_cast_fixit): Same. - (cp_parser_template_introduction): Same. - * typeck.c (access_failure_info::add_fixit_hint): Same. - -2020-11-25 Thomas Schwinge <thomas@codesourcery.com> - - * pt.c (tsubst_omp_clauses): Handle 'OMP_CLAUSE__CACHE_'. - (tsubst_expr): Handle 'OACC_CACHE'. - -2020-11-24 Jason Merrill <jason@redhat.com> - - PR c++/97899 - * typeck2.c (store_init_value): Don't split_nonconstant_init in a - template. - -2020-11-24 Jakub Jelinek <jakub@redhat.com> - - PR tree-optimization/96929 - * constexpr.c (cxx_eval_binary_expression): For shifts by constant - with MSB set, emulate older wide_int_binop behavior to preserve - diagnostics and -fpermissive behavior. - -2020-11-23 Nathan Sidwell <nathan@acm.org> - - * module.cc: New dummy file. - * Make-lang.in: Add rules to build module.o - -2020-11-23 Jozef Lawrynowicz <jozef.l@mittosystems.com> - - * decl.c (start_decl): Set DECL_INITIAL for initialized decls - before attribute processing. - -2020-11-23 Richard Sandiford <richard.sandiford@arm.com> - - PR c++/97904 - * pt.c (tsubst): Use verify_type_context to check the type - of an array element. - -2020-11-21 Marek Polacek <polacek@redhat.com> - - PR c++/94695 - * parser.c (warn_for_range_copy): Warn when the loop variable is - initialized with a value of a different type resulting in a copy. - -2020-11-21 Marek Polacek <polacek@redhat.com> - - PR c++/97846 - * constexpr.c (potential_constant_expression_1): Reject - LABEL_EXPRs that use non-artifical LABEL_DECLs. - -2020-11-21 Marek Polacek <polacek@redhat.com> - - PR c++/97881 - * parser.c (warn_about_ambiguous_parse): Only assume "int" if we - actually saw any type-specifiers. - -2020-11-21 Marek Polacek <polacek@redhat.com> - - PR c++/97839 - * parser.c (cp_parser_lambda_declarator_opt): Don't require (). - -2020-11-21 Marek Polacek <polacek@redhat.com> - - PR c++/97427 - * constexpr.c (cxx_set_object_constness): New function. - (cxx_eval_call_expression): Set new_obj for destructors too. - Call cxx_set_object_constness to set/unset TREE_READONLY of - the object under construction/destruction. - -2020-11-21 Aaron Sawdey <acsawdey@linux.ibm.com> - - * error.c (dump_type): Handle opaque types. - (dump_type_prefix): Handle opaque types. - (dump_type_suffix): Handle opaque types. - (dump_expr): Handle opaque types. - * pt.c (tsubst): Allow opaque types in templates. - (unify): Allow opaque types in templates. - * typeck.c (structural_comptypes): Handle comparison - of opaque types. - -2020-11-20 Jakub Jelinek <jakub@redhat.com> - - PR other/97911 - * Make-lang.in (c++.serial): Change from goal to a variable. - (.PHONY): Drop c++.serial and c++.prev. - (cc1plus$(exeext)): Depend on $(c++.serial) rather than c++.serial. - -2020-11-19 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (struct spec_entry): Moved from pt.c. - (walk_specializations, match_mergeable_specialization) - (get_mergeable_specialization_flags) - (add_mergeable_specialization): Declare. - * pt.c (struct spec_entry): Moved to cp-tree.h. - (walk_specializations, match_mergeable_specialization) - (get_mergeable_specialization_flags) - (add_mergeable_specialization): New. - -2020-11-19 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (struct constexpr_fundef): Moved from constexpr.c. - (maybe_save_constexpr_fundef): Declare. - (register_constexpr_fundef): Take constexpr_fundef object, return - void. - * decl.c (mabe_save_function_definition): Delete, functionality - moved to maybe_save_constexpr_fundef. - (emit_coro_helper, finish_function): Adjust. - * constexpr.c (struct constexpr_fundef): Moved to cp-tree.h. - (constexpr_fundef_hasher::equal): Constify. - (constexpr_fundef_hasher::hash): Constify. - (retrieve_constexpr_fundef): Make non-static. - (maybe_save_constexpr_fundef): Break out checking and duplication - from ... - (register_constexpr_fundef): ... here. Just register the constexpr. - -2020-11-19 Marek Polacek <polacek@redhat.com> - - PR c++/97523 - * init.c (build_new): When value-initializing an array new, - leave the INIT as an empty vector. - -2020-11-19 Marek Polacek <polacek@redhat.com> - - PR c++/97895 - * pt.c (do_auto_deduction): Don't crash when the constructor has - zero elements. - -2020-11-19 Nathan Sidwell <nathan@acm.org> - - PR c++/97905 - * decl.c (duplicate_decls): Relax new assert. - -2020-11-18 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_objc_valid_prefix_attributes): Check - for empty attributes. - -2020-11-18 Jakub Jelinek <jakub@redhat.com> - - * Make-lang.in (c++.serial): New goal. - (.PHONY): Add c++.serial c++.prev. - (cc1plus$(exeext)): Depend on c++.prev. Call LINK_PROGRESS. - -2020-11-17 Nathan Sidwell <nathan@acm.org> - - PR c++/97877 - * decl.c (duplicate_decls): Deal with duplicated DECL_LOCAL_DECL_P - decls. Extend decl_lang_specific checking assert. - -2020-11-17 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (enum cp_tree_index): Reorder to place lazy fields - after newly-added CPTI_MODULE_HWM. - -2020-11-17 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/97871 - * parser.c (cp_parser_declaration): Remove checking assert. - -2020-11-15 Jason Merrill <jason@redhat.com> - - * decl.c (cp_finish_decl): Only check abstractness on definition. - (require_complete_types_for_parms): Check abstractness here. - (create_array_type_for_decl): Not here. - (grokdeclarator, grokparms, complete_vars): Not here. - * pt.c (tsubst, tsubst_arg_types, tsubst_function_type): Not here. - * typeck2.c (struct pending_abstract_type): Remove. - (struct abstract_type_hasher): Remove. - (abstract_pending_vars, complete_type_check_abstract): Remove. - (abstract_virtuals_error_sfinae): Handle arrays. - * call.c (conv_is_prvalue): Split out from... - (conv_binds_ref_to_prvalue): ...here. - (implicit_conversion_1): Rename from implicit_conversion. - (implicit_conversion): An abstract prvalue is bad. - (convert_like_internal): Don't complain if expr is already - error_mark_node. - -2020-11-13 Jason Merrill <jason@redhat.com> - - * cp-tree.h (USING_DECL_UNRELATED_P): New. - (CONST_DECL_USING_P): New. - * class.c (handle_using_decl): If USING_DECL_UNRELATED_P, - clone the CONST_DECL. - * name-lookup.c (supplement_binding_1): A clone hides its - using-declaration. - (lookup_using_decl): Rewrite to separate lookup and validation. - (do_class_using_decl): Adjust. - (finish_nonmember_using_decl): Adjust. - * parser.c (make_location): Add cp_token overload. - (finish_using_decl): Split out from... - (cp_parser_using_declaration): ...here. Don't look through enums. - (cp_parser_using_enum): New. - (cp_parser_block_declaration): Call it. - (cp_parser_member_declaration): Call it. - * semantics.c (finish_id_expression_1): Handle enumerator - used from class scope. - -2020-11-13 Vladimir N. Makarov <vmakarov@redhat.com> - - * parser.c (cp_parser_asm_definition): Parse outputs for asm - goto too. - -2020-11-13 Iain Sandoe <iain@sandoe.co.uk> - - PR objc/77404 - * parser.c (cp_parser_objc_class_interface): Pass the - location of the class name to the interface declaration. - -2020-11-13 Patrick Palka <ppalka@redhat.com> - - * semantics.c (finish_compound_literal): Don't wrap the original - compound literal in a TARGET_EXPR when inside a template. - -2020-11-12 Jakub Jelinek <jakub@redhat.com> - - PR c++/97790 - * constexpr.c (cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR, - case TRY_FINALLY_EXPR, case CLEANUP_STMT>: Don't pass jump_target to - cxx_eval_constant_expression when evaluating the cleanups. - -2020-11-11 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_declaration): Unless we are compiling for - Ojective-C++, warn about and discard any attributes that prefix - a linkage specification. - -2020-11-11 Patrick Palka <ppalka@redhat.com> - - PR c++/88115 - * mangle.c (write_expression): Mangle __alignof_ differently - from alignof when the ABI version is at least 15. - -2020-11-11 Patrick Palka <ppalka@redhat.com> - - PR c++/88115 - * cp-tree.h (cxx_sizeof_or_alignof_expr): Add bool parameter. - * decl.c (fold_sizeof_expr): Pass false to - cxx_sizeof_or_alignof_expr. - * parser.c (cp_parser_unary_expression): Pass std_alignof to - cxx_sizeof_or_alignof_expr. - * pt.c (tsubst_copy): Pass false to cxx_sizeof_or_alignof_expr. - (tsubst_copy_and_build): Pass std_alignof to - cxx_sizeof_or_alignof_expr. - * typeck.c (cxx_alignof_expr): Add std_alignof bool parameter - and pass it to cxx_sizeof_or_alignof_type. Set ALIGNOF_EXPR_STD_P - appropriately. - (cxx_sizeof_or_alignof_expr): Add std_alignof bool parameter - and pass it to cxx_alignof_expr. Assert op is either - SIZEOF_EXPR or ALIGNOF_EXPR. - -2020-11-11 Marek Polacek <polacek@redhat.com> - - PR c++/97518 - * pt.c (tsubst_qualified_id): Use EXPR_LOCATION of the qualified-id. - Use it to maybe_wrap_with_location the final expression. - -2020-11-10 Marek Polacek <polacek@redhat.com> - - PR c++/97518 - * cp-tree.h (finish_static_assert): Adjust declaration. - * parser.c (cp_parser_static_assert): Pass false to - finish_static_assert. - * pt.c (tsubst_expr): Pass true to finish_static_assert. - * semantics.c (find_failing_clause_r): New function. - (find_failing_clause): New function. - (finish_static_assert): Add a bool parameter. Use - iloc_sentinel. Call contextual_conv_bool instead of - perform_implicit_conversion_flags. Don't check for INTEGER_CST before - calling integer_zerop. Call find_failing_clause and maybe use its - location. Print the original condition or the failing clause if - SHOW_EXPR_P. - -2020-11-10 Strager Neds <strager.nds@gmail.com> - - * decl.c (duplicate_decls): Use new overload of - set_decl_section_name. - * method.c (use_thunk): Same. - * optimize.c (maybe_clone_body): Same. - * coroutines.cc (act_des_fn): Same. - -2020-11-10 Jakub Jelinek <jakub@redhat.com> - - PR c/97748 - * cvt.c (convert_to_void): Check (complain & tf_warning) in the outer - if rather than twice times in the inner one. Use warn_if_unused_value. - Formatting fix. - -2020-11-10 Chung-Lin Tang <cltang@codesourcery.com> - - * parser.c (cp_parser_omp_target_data): Add use of - new c_omp_adjust_map_clauses function. Add GOMP_MAP_ATTACH_DETACH as - handled map clause kind. - (cp_parser_omp_target_enter_data): Likewise. - (cp_parser_omp_target_exit_data): Likewise. - (cp_parser_omp_target): Likewise. - * semantics.c (handle_omp_array_sections): Adjust COMPONENT_REF case to - use GOMP_MAP_ATTACH_DETACH map kind for C_ORT_OMP region type. Fix - interaction between reference case and attach/detach. - (finish_omp_clauses): Adjust bitmap checks to allow struct decl and - same struct field access to co-exist on OpenMP construct. - -2020-11-09 Marek Polacek <polacek@redhat.com> - - DR 1914 - * parser.c (cp_parser_check_std_attribute): Return bool. Add a - location_t parameter. Return true if the attribute wasn't duplicated. - Give a warning instead of an error. Check more attributes. - (cp_parser_std_attribute_list): Don't add duplicated attributes to - the list. Pass location to cp_parser_check_std_attribute. - -2020-11-09 Patrick Palka <ppalka@redhat.com> - - * constraint.cc (norm_info::norm_info): Initialize orig_decl. - (norm_info::orig_decl): New data member. - (normalize_atom): When caching an atom for the first time, - compute a list of template parameters used in the targets of the - parameter mapping and store it in the TREE_TYPE of the mapping. - (get_normalized_constraints_from_decl): Set current_function_decl - appropriately when normalizing. As an optimization, don't - set up a push_nested_class_guard when decl has no constraints. - (sat_hasher::hash): Use this list to hash only the template - arguments that are relevant to the atom. - (satisfy_atom): Use this list to compare only the template - arguments that are relevant to the atom. - * pt.c (keep_template_parm): Do a sanity check on the parameter's - index when flag_checking. - -2020-11-09 Patrick Palka <ppalka@redhat.com> - - * cp-tree.h (ATOMIC_CONSTR_MAP_INSTANTIATED_P): Define this flag - for ATOMIC_CONSTRs. - * constraint.cc (sat_hasher::hash): Use hash_atomic_constraint - if the flag is set, otherwise keep using a pointer hash. - (sat_hasher::equal): Return false if the flag's setting differs - on two atoms. Call atomic_constraints_identical_p if the flag - is set, otherwise keep using a pointer equality test. - (satisfy_atom): After instantiating the parameter mapping, form - another ATOMIC_CONSTR using the instantiated mapping and query - the cache again. Cache the satisfaction value of both atoms. - (diagnose_atomic_constraint): Simplify now that the supplied - atom has an instantiated mapping. - -2020-11-09 Patrick Palka <ppalka@redhat.com> - - * constraint.cc (atom_cache): Define this deletable hash_table. - (normalize_atom): Use it to cache ATOMIC_CONSTRs when not - generating diagnostics. - (sat_hasher::hash): Use htab_hash_pointer instead of - hash_atomic_constraint. - (sat_hasher::equal): Test for pointer equality instead of - atomic_constraints_identical_p. - * cp-tree.h (struct atom_hasher): Moved and renamed from ... - * logic.cc (struct constraint_hash): ... here. - (clause::m_set): Adjust accordingly. - -2020-11-09 Patrick Palka <ppalka@redhat.com> - - PR c++/93907 - * constraint.cc (tsubst_parameter_mapping): Also canonicalize - the type arguments of a TYPE_ARGUMENT_PACk. - -2020-11-09 Jason Merrill <jason@redhat.com> - - * pt.c (tsubst): Replace *_ARGUMENT_PACK code with - a call to tsubst_argument_pack. - -2020-11-09 Jason Merrill <jason@redhat.com> - - * class.c (handle_using_decl): Add an iloc_sentinel. - -2020-11-09 Marek Polacek <polacek@redhat.com> - - PR c++/97762 - * parser.c (warn_about_ambiguous_parse): Handle the case when - there is no type in the decl-specifiers. - -2020-11-09 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (LOOKUP_FOUND_P): Add ENUMERAL_TYPE. - * name-lookup.c (class name_lookup): Add comments. - (name_lookup::adl_namespace_only): Replace with ... - (name_lookup::adl_class_fns): ... this and ... - (name_lookup::adl_namespace_fns): ... this. - (name_lookup::adl_namespace): Deal with inline nests here. - (name_lookup::adl_class): Complete the type here. - (name_lookup::adl_type): Call broken-out enum .. - (name_lookup::adl_enum): New. No need to call the namespace adl - if it is class-scope. - (name_lookup::search_adl): Iterate over collected scopes here. - -2020-11-09 Nathan Sidwell <nathan@acm.org> - - * name-lookup.c (lookup_qualified_name): Expose an overload of a - singleton with known type. - (lookup_name_1): Just check the overload's type to expose it. - * parser.c (cp_parser_lookup_name): Do not do that check here. - -2020-11-08 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_objc_at_property_declaration): Handle - class keywords in @property attribute context. - -2020-11-06 Marek Polacek <polacek@redhat.com> - - PR c++/81660 - * except.c (can_convert_eh): Change the return type to bool. If - the type TO and FROM are the same, return true. - -2020-11-06 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_objc_at_property_declaration): - Improve parsing fidelity. Associate better location info - with @property attributes. Clean up the interface to - objc_add_property_declaration (). - -2020-11-06 Jakub Jelinek <jakub@redhat.com> - - PR c++/67453 - * decl.c (duplicate_decls): Propagate DECL_ATTRIBUTES and - DECL_PRESERVE_P from olddecl to its clones if any. - -2020-11-06 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (DECL_UNDECLARED_BUILTIN_P): Delete. - * cp-objcp-common.c (names_bultin_p): Rename - DECL_IS_BUILTIN->DECL_IS_UNDECLARED_BUILTIN. - * decl.c (decls_match): Likewise. Replace - DECL_UNDECLARED_BUILTIN_P with DECL_IS_UNDECLARED_BUILTIN. - (duplicate_decls): Likewise. - * decl2.c (collect_source_refs): Likewise. - * name-lookup.c (anticipated_builtin_p, print_binding_level) - (do_nonmember_using_decl): Likewise. - * pt.c (builtin_pack_fn_p): Likewise. - * typeck.c (error_args_num): Likewise. - -2020-11-06 Nathan Sidwell <nathan@acm.org> - - * parser.c (cp_parser_template_declaration): Adjust 'export' warning. - (cp_parser_explicit_specialization): Remove unneeded bool setting. - -2020-11-06 Jan Hubicka <jh@suse.cz> - - * tree.c (cp_fix_function_decl_p): Do not access ipa_ref_list dirrectly. - -2020-11-06 Tobias Burnus <tobias@codesourcery.com> - - * parser.c (cp_parser_omp_atomic): Add openacc parameter and update - OpenACC matching. - (cp_parser_omp_construct): Update call. - -2020-11-05 Marek Polacek <polacek@redhat.com> - - * except.c (check_handlers_1): Add auto_diagnostic_group. - -2020-11-05 Marek Polacek <polacek@redhat.com> - - PR c++/78209 - * pt.c (do_auto_deduction): If init is REFERENCE_REF_P, use its - first operand. - -2020-11-05 Marek Polacek <polacek@redhat.com> - - PR c++/97675 - * except.c (check_handlers_1): Use OPT_Wexceptions for the - warning. Use inform for the second part of the warning. - -2020-11-05 Marek Polacek <polacek@redhat.com> - - PR c++/25814 - * cp-tree.h (enum cp_tree_index): Add CPTI_EXPLICIT_VOID_LIST. - (explicit_void_list_node): Define. - (PARENTHESIZED_LIST_P): New macro. - (struct cp_declarator): Add function::parens_loc. - * decl.c (cxx_init_decl_processing): Initialize explicit_void_list_node. - (grokparms): Also break when explicit_void_list_node. - * parser.c (make_call_declarator): New location_t parameter. Use it - to set declarator->u.function.parens_loc. - (cp_parser_lambda_declarator_opt): Pass UNKNOWN_LOCATION to - make_call_declarator. - (warn_about_ambiguous_parse): New function. - (cp_parser_init_declarator): Call warn_about_ambiguous_parse. - (cp_parser_declarator): Set *parenthesized_p to false rather than to - true. - (cp_parser_direct_declarator): Create a location for the function's - parentheses and pass it to make_call_declarator. - (cp_parser_parameter_declaration_clause): Return explicit_void_list_node - for (void). - (cp_parser_parameter_declaration_list): Set PARENTHESIZED_LIST_P - in the parameters tree. - -2020-11-04 Jakub Jelinek <jakub@redhat.com> - - PR c++/97670 - * semantics.c (finish_omp_clauses): Look through array reductions to - find underlying decl to clear in the aligned_head bitmap. Use - DECL_UID (t) instead of DECL_UID (OMP_CLAUSE_DECL (c)) when clearing - in the bitmap. Only diagnose errors about allocate vars not being - privatized on the same construct on allocate clause if it has - a DECL_P OMP_CLAUSE_DECL. - -2020-11-04 Iain Sandoe <iain@sandoe.co.uk> - - * constexpr.c (potential_constant_expression_1): Handle - expressions known to be non-constant for Objective-C. - -2020-11-03 Jason Merrill <jason@redhat.com> - - * tree.c (is_byte_access_type): Don't use char_type_p. - -2020-11-03 Jakub Jelinek <jakub@redhat.com> - - PR c++/97663 - * parser.c (cp_parser_init_declarator): Don't try to parse - C++17 deduction guides if there are any type specifiers even when - type is NULL. - -2020-11-03 Kamlesh Kumar <kamleshbhalui@gmail.com> - Jason Merrill <jason@redhat.com> - - PR c++/97453 - DR2303 - * pt.c (get_template_base): Consider closest base in template - deduction when base of base also matches. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * pt.c (tsubst_expr): Simplify using decl instantiation, add - asserts. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * class.c (copy_fndecl_with_name): Always not top level. - (build_cdtor_clones): Add update_methods parm, use it to - conditionally update the method vec. Return void - (clone_cdtor): Adjust. - (clone_constructors_and_destructors): Adjust comment. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * pt.c (primary_template_specialization_p): Use - VAR_OR_FUNCTION_DECL_P. - (tsubst_template_decl): Check for FUNCTION_DECL, not !TYPE && !VAR - for registering a specialization. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (fixup_deferred_exception_variants): Declare. - * parser.c (cp_parser_class_specifier_1): Call it when - completing deferred parses rather than creating a variant. - (cp_parser_member_declaration): Move comment from ... - (cp_parser_noexcept_specification_opt): ... here. Refactor the - deferred parse. - * tree.c (fixup_deferred_exception_variants): New. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * pt.c (tsubst_lambda_expr): Reorder extra-scope handling to match - the non-template case. - (instantiate_body): Move a couple of declarations to their - initializers. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * decl.c (duplicate_decls): Return error_mark_node fo extern-c - mismatch. - -2020-11-03 Marek Polacek <polacek@redhat.com> - - * constexpr.c (potential_constant_expression_1): Treat - __PRETTY_FUNCTION__ inside a template function as - potentially-constant. - * pt.c (uses_template_parms): Call - instantiation_dependent_expression_p instead of - value_dependent_expression_p. - (instantiation_dependent_expression_p): Check - potential_constant_expression before calling - value_dependent_expression_p. - -2020-11-03 Marek Polacek <polacek@redhat.com> - - PR c++/97632 - * init.c (build_new_1): Disable -Winit-list-lifetime for an unevaluated - operand. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * tree.c (bind_template_template_parm): Mark the parm as a - template parm. - (cp_tree_equal): Refactor CALL_EXPR. Use comp_template_args for - TREE_VECs. - -2020-11-03 Nathan Sidwell <nathan@acm.org> - - * rtti.c (init_rtti_processing): Move var decl to its init. - (get_tinfo_decl): Likewise. Break out creation to called helper - ... - (get_tinfo_decl_direct): ... here. - (build_dynamic_cast_1): Move var decls to their initializers. - (tinfo_base_init): Set decl's location to BUILTINS_LOCATION. - (get_tinfo_desc): Only push ABI namespace when needed. Set type's - context. - -2020-11-02 Nathan Sidwell <nathan@acm.org> - - * decl.c (start_decl_1): Refactor declarations. Fixup some - whitespace. - (lookup_and_check_tag): Fixup some whitespace. - -2020-11-02 Nathan Sidwell <nathan@acm.org> - - * decl.c (duplicate_decls): Refactor some template & builtin - handling. - -2020-11-02 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (struct cxx_int_tree_map): Delete. - (struct cxx_int_tree_map_hasher): Delete. - * cp-gimplify.c (cxx_int_tree_map_hasher::equal): Delete. - (cxx_int_tree_map_hasher::hash): Delete. - -2020-11-02 Patrick Palka <ppalka@redhat.com> - - * class.c (finish_struct_1): Don't call clear_satisfaction_cache. - * constexpr.c (clear_cv_and_fold_caches): Likewise. Remove bool - parameter. - * constraint.cc (clear_satisfaction_cache): Remove definition. - * cp-tree.h (clear_satisfaction_cache): Remove declaration. - (clear_cv_and_fold_caches): Remove bool parameter. - * typeck2.c (store_init_value): Remove argument to - clear_cv_and_fold_caches. - -2020-11-01 Iain Sandoe <iain@sandoe.co.uk> - - * parser.c (cp_parser_objc_at_property_declaration): Use any - exisiting syntax error to suppress complaints about a missing - closing parenthesis in parsing property attributes. - -2020-10-30 Jakub Jelinek <jakub@redhat.com> - - * semantics.c (finish_omp_clauses) <case OMP_CLAUSE_ALLOCATE>: Handle - non-static members in methods. - * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_ALLOCATE. - -2020-10-29 Marek Polacek <polacek@redhat.com> - - DR 625 - PR c++/97479 - * parser.c (cp_parser_type_id_1): Reject using auto as - a template-argument in C++20. - -2020-10-29 Marek Polacek <polacek@redhat.com> - - PR c++/93107 - * pt.c (do_auto_deduction): Call resolve_nondeduced_context for - the elements of a { } list. - -2020-10-29 Marek Polacek <polacek@redhat.com> - - * typeck.c (do_warn_enum_conversions): Don't warn for SPACESHIP_EXPR. - (cp_build_binary_op): Reject float <=> enum or enum <=> float. Use - CP_INTEGRAL_TYPE_P instead of INTEGRAL_OR_ENUMERATION_TYPE_P. - -2020-10-29 Patrick Palka <ppalka@redhat.com> - - * constraint.cc (get_normalized_constraints): Remove 'args' - parameter. Pass NULL_TREE as the initial template arguments to - normalize_expression. - (get_normalized_constraints_from_info): Remove 'args' parameter - and adjust the call to get_normalized_constraints. - (get_normalized_constraints_from_decl): Remove 'args' local - variable and adjust call to get_normalized_constraints_from_info. - (normalize_concept_definition): Remove 'args' local variable - and adjust call to get_normalized_constraints. - (normalize_constraint_expression): Remove the two-parameter - overload. Remove 'args' parameter from the three-parameter - overload and update function comment accordingly. Remove - default argument from 'diag' parameter. Adjust call to - get_normalized_constraints. - (finish_nested_requirement): Adjust call to - normalize_constraint_expression. - (strictly_subsumes): Remove 'args' parameter. Adjust call to - get_normalized_constraints_from_info. - (weakly_subsumes): Likewise. - * cp-tree.h (strictly_subsumes): Remove 'args' parameter. - (weakly_subsumes): Likewise. - * pt.c (process_partial_specialization): Adjust call to - strictly_subsumes. - (is_compatible_template_arg): Adjust call to weakly_subsumes. - -2020-10-29 Patrick Palka <ppalka@redhat.com> - - PR c++/97412 - * constraint.cc (normalize_concept_check): Don't call - tsubst_template_args when 'args' is NULL. - -2020-10-29 Jason Merrill <jason@redhat.com> - - PR c++/97388 - * constexpr.c (cxx_eval_outermost_constant_expr): Revert to - original expression if evaluation sets non_constant_p. - -2020-10-29 Jakub Jelinek <jakub@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/97388 - * constexpr.c (cxx_bind_parameters_in_call): Set non_constant_args - if the parameter type has a non-trivial destructor. - (cxx_eval_call_expression): Only unshare arguments if we're - memoizing this evaluation. - -2020-10-29 Jakub Jelinek <jakub@redhat.com> - - PR c++/95808 - * cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_VEC_UNINIT_IDENTIFIER - and CPTI_HEAP_VEC_IDENTIFIER. - (heap_vec_uninit_identifier, heap_vec_identifier): Define. - * decl.c (initialize_predefined_identifiers): Initialize those - identifiers. - * constexpr.c (cxx_eval_call_expression): Reject array allocations - deallocated with non-array deallocation or non-array allocations - deallocated with array deallocation. - (non_const_var_error): Handle heap_vec_uninit_identifier and - heap_vec_identifier too. - (cxx_eval_constant_expression): Handle also heap_vec_uninit_identifier - and in that case during initialization replace it with - heap_vec_identifier. - (find_heap_var_refs): Handle heap_vec_uninit_identifier and - heap_vec_identifier too. - -2020-10-29 Nathan Sidwell <nathan@acm.org> - - * pt.c (push_template_decl): Do not give function-scope entities - other than implicit typedefs a template header. Do not readd - template info to a redeclared template. - -2020-10-28 Marek Polacek <polacek@redhat.com> - - * decl.c (grokdeclarator): Offer a fix-it hint for the "unnecessary - parentheses in declaration" warning. - * parser.c (cp_parser_direct_declarator): When setting - declarator->parenthesized, use a location range. - -2020-10-28 Marek Polacek <polacek@redhat.com> - - PR c++/97573 - * call.c (build_conditional_expr_1): Warn about the deprecated - enum/real type conversion in C++20. Also warn about a non-enumerated - and enumerated type in ?: when -Wenum-conversion is on. - * typeck.c (do_warn_enum_conversions): New function. - (cp_build_binary_op): Call it. - -2020-10-28 Marek Polacek <polacek@redhat.com> - - PR c++/96675 - PR c++/96742 - * pt.c (tsubst_copy_and_build): Call value_dependent_expression_p or - type_dependent_expression_p instead of type_dependent_expression_p_push. - But only call value_dependent_expression_p for expressions that are - potential_constant_expression. - -2020-10-28 Marek Polacek <polacek@redhat.com> - - PR c++/94799 - * parser.c (cp_parser_class_name): Use parser->scope when - setting typename_p. - -2020-10-28 Marek Polacek <polacek@redhat.com> - - PR c++/86773 - * parser.c (cp_parser_fold_expression): Return error_mark_node - if a left fold is preceded by an expression. - -2020-10-28 Nathan Sidwell <nathan@acm.org> - - * parser.c (cp_parser_omp_declare_reduction): Set - DECL_LOCAL_DECL_P before push_template_decl. - * pt.c (instantiate_body): Nested fns do not have template_info. - -2020-10-28 Patrick Palka <ppalka@redhat.com> - - PR c++/95132 - * decl2.c (mark_used): Move up the constraints_satisfied_p check - so that we check constraints before calling maybe_instantiate_decl. - -2020-10-28 Nathan Sidwell <nathan@acm.org> - - * pt.c (push_template_decl): Refactor for some RAII. - -2020-10-28 Jakub Jelinek <jakub@redhat.com> - - * parser.c (cp_parser_omp_clause_name): Handle allocate. - (cp_parser_omp_clause_allocate): New function. - (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_ALLOCATE. - (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, - OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, - OMP_TASK_CLAUSE_MASK, OMP_TASKGROUP_CLAUSE_MASK, - OMP_DISTRIBUTE_CLAUSE_MASK, OMP_TEAMS_CLAUSE_MASK, - OMP_TARGET_CLAUSE_MASK, OMP_TASKLOOP_CLAUSE_MASK): Add - PRAGMA_OMP_CLAUSE_ALLOCATE. - * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_ALLOCATE. - * pt.c (tsubst_omp_clauses): Likewise. - -2020-10-27 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (struct lang_type): Delete nested_udts field. - (CLASSTYPE_NESTED_UTDS): Delete. - * name-lookup.h (binding_table, binding_entry): Delete typedefs. - (bt_foreach_proc): Likewise. - (struct binding_entry_s): Delete. - (SCOPE_DEFAULT_HT_SIZE, CLASS_SCOPE_HT_SIZE) - (NAMESPACE_ORDINARY_HT_SIZE, NAMESPACE_STD_HT_SIZE) - (GLOBAL_SCOPE_HT_SIZE): Delete. - (binding_table_foreach, binding_table_find): Delete declarations. - * name-lookup.c (ENTRY_INDEX): Delete. - (free_binding_entry): Delete. - (binding_entry_make, binding_entry_free): Delete. - (struct binding_table_s): Delete. - (binding_table_construct, binding_table_free): Delete. - (binding_table_new, binding_table_expand): Delete. - (binding_table_insert, binding_table_find): Delete. - (binding_table_foreach): Delete. - (maybe_process_template_type_declaration): Delete - CLASSTYPE_NESTED_UTDS insertion. - (do_pushtag): Likewise. - * decl2.c (bt_reset_linkage_1): Fold into reset_type_linkage_1. - (reset_type_linkage_2, bt_reset_linkage_2): Fold into - reset_type_linkage. - * pt.c (instantiate_class_template_1): Delete NESTED_UTDs comment. - (bt_instantiate_type_proc): Delete. - (do_type_instantiation): Instantiate implicit typedef fields. - Delete NESTED_UTD walk. - * search.c (lookup_field_r): Delete unreachable NESTED_UTD - search. - -2020-10-27 Nathan Sidwell <nathan@acm.org> - - * parser.c (cp_parser_explicit_instantiation): Refactor some RAII. - * pt.c (bt_instantiate_type_proc): DATA is the tree, pass type to - do_type_instantiation. - (do_type_instantiation): Require T to be a type. Refactor for - some RAII. - -2020-10-26 Ville Voutilainen <ville.voutilainen@gmail.com> - - * cp-tree.h (CPTK_IS_NOTHROW_ASSIGNABLE): New. - (CPTK_IS_NOTHROW_CONSTRUCTIBLE): Likewise. - (is_nothrow_xible): Likewise. - * method.c (is_nothrow_xible): New. - (is_trivially_xible): Tweak. - * parser.c (cp_parser_primary_expression): Handle the new RID_*. - (cp_parser_trait_expr): Likewise. - * semantics.c (trait_expr_value): Handle the new RID_*. - (finish_trait_expr): Likewise. - -2020-10-24 Marek Polacek <polacek@redhat.com> - - PR c++/96241 - * constexpr.c (cxx_eval_array_reference): Set up ctx->ctor if we - are initializing an aggregate. Call free_constructor on the new - CONSTRUCTOR if it isn't returned from cxx_eval_constant_expression. - -2020-10-23 Marek Polacek <polacek@redhat.com> - - PR c++/91741 - * typeck.c (cp_build_binary_op): Implement -Wsizeof-array-div. - -2020-10-22 Patrick Palka <ppalka@redhat.com> - - PR c++/97328 - * constexpr.c (init_subob_ctx): Don't punt on RANGE_EXPR - indexes, instead build a sub-aggregate initialization context - with no subobject. - -2020-10-22 Patrick Palka <ppalka@redhat.com> - - PR c++/96575 - * constexpr.c (cxx_eval_constant_expression) - <case EMPTY_CLASS_EXPR>: Lower it to a CONSTRUCTOR. - (potential_constant_expression_1) <case COMPOUND_EXPR>: Remove - now-redundant handling of COMPOUND_EXPR with EMPTY_CLASS_EXPR - second operand. - <case EMPTY_CLASS_EXPR>: Return true instead of false. - -2020-10-22 Patrick Palka <ppalka@redhat.com> - - PR c++/97511 - * decl.c (duplicate_decls): Return NULL_TREE if - DECL_TEMPLATE_PARM_P differ. - -2020-10-20 Nathan Sidwell <nathan@acm.org> - - * name-lookup.c (push_local_extern_decl_alias): Reconstextualize - alias' parm decls. Drop any default args. - -2020-10-19 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/97438 - * coroutines.cc (struct coroutine_info): Add a field to - record that we emitted a promise type error. - (coro_promise_type_found_p): Check for the case that the - promise type contains both return_void and return_value. - Emit an error if so, with information about the wrong - type methods. - -2020-10-16 Nathan Sidwell <nathan@acm.org> - - PR c++/97460 - * pt.c (push_template_decl): Check DECL_LANG_SPECIFIC in friend - case. - -2020-10-16 Nathan Sidwell <nathan@acm.org> - - PR c++/96258 - * parser.c (cp_parser_declaration): Make token2 point to EOF if - token1 was EOF. - -2020-10-15 Jason Merrill <jason@redhat.com> - - PR c++/95844 - * decl.c (copy_fn_p): Return false for a function that is neither a - constructor nor an assignment operator. - (move_signature_fn_p): Likewise. - -2020-10-15 Marek Polacek <polacek@redhat.com> - - PR c++/97406 - PR c++/85901 - * cxx-pretty-print.c (pp_cxx_type_specifier_seq): Handle OFFSET_TYPE. - (cxx_pretty_printer::abstract_declarator): Fix the printing of ')'. - (cxx_pretty_printer::direct_abstract_declarator): Handle OFFSET_TYPE. - (cxx_pretty_printer::type_id): Likewise. Print the abstract declarator - for pointers-to-members. - -2020-10-14 Jason Merrill <jason@redhat.com> - - PR c++/97358 - * pt.c (check_for_bare_parameter_packs): Diagnose use of - capture pack. - -2020-10-14 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (struct lang_decl_fn): Adjust context comment. - (DECL_FRIEND_P): Replace with ... - (DECL_UNIQUE_FRIEND_P): ... this. Only for FUNCTION_DECLs. - (DECL_FRIEND_CONTEXT): Adjust. - * class.c (add_implicitly_declared_members): Detect friendly - spaceship from context. - * constraint.cc (remove_constraints): Use a checking assert. - (maybe_substitute_reqs_for): Use DECL_UNIQUE_FRIEND_P. - * decl.c (check_no_redeclaration_friend_default_args): - DECL_UNIQUE_FRIEND_P is signficant, not hiddenness. - (duplicate_decls): Adjust DECL_UNIQUE_FRIEND_P clearing. - (redeclaration_error_message): Use DECL_UNIQUE_FRIEND_P. - (start_preparsed_function): Correct in-class friend processing. - Refactor some initializers. - (grokmethod): Directly check friend decl-spec. - * decl2.c (grokfield): Check DECL_UNIQUE_FRIEND_P. - * friend.c (do_friend): Set DECL_UNIQUE_FRIEND_P first, remove - extraneous conditions. Don't re set it afterwards. - * name-lookup.c (lookup_elaborated_type_1): Simplify revealing - code. - (do_pushtag): Likewise. - * pt.c (optimize_specialization_lookup_p): Check - DECL_UNIQUE_FRIEND_P. - (push_template_decl): Likewise. Drop unneeded friend setting. - (type_dependent_expression_p): Check DECL_UNIQUE_FRIEND_P. - -2020-10-14 Nathan Sidwell <nathan@acm.org> - - * name-lookup.c (push_local_extern_decl_alias): Push into alias's - namespace and use pushdecl. - (do_pushdecl_with_scope): Clarify behaviour. - -2020-10-12 Martin Sebor <msebor@redhat.com> - - PR c++/97201 - * error.c (dump_type_suffix): Handle both the C and C++ forms of - zero-length arrays. - -2020-10-12 Martin Sebor <msebor@redhat.com> - - PR c++/96511 - PR middle-end/96384 - * init.c (warn_placement_new_too_small): Call builtin_objsize instead - of duplicating what it does. - -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. + PR c++/98570 * 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. - * mangle.c (write_expression): Express unions with a designator. - -2020-07-10 Jason Merrill <jason@redhat.com> - - * pt.c (convert_nontype_argument): Handle REAL_TYPE. - (invalid_nontype_parm_type_p): Allow all structural types. - * tree.c (structural_type_p): Use SCALAR_TYPE_P. - -2020-07-10 Jason Merrill <jason@redhat.com> - - PR c++/96105 - PR c++/96052 - PR c++/95976 - * class.c (check_field_decls): An array of empty classes is not an - empty data member. - (layout_empty_base_or_field): Handle explicit alignment. - Fix union handling. - -2020-07-09 Julian Brown <julian@codesourcery.com> - Thomas Schwinge <thomas@codesourcery.com> - - PR middle-end/95270 - * semantics.c (finish_omp_clauses): Likewise. - -2020-07-09 Patrick Palka <ppalka@redhat.com> - - PR c++/96132 - * constexpr.c (potential_constant_expression_1) <case PARM_DECL>: - Restore dependent_type_p check that guarded the call to - is_really_empty_class. - -2020-07-08 Patrick Palka <ppalka@redhat.com> - - PR c++/95497 - * constexpr.c (potential_constant_expression_1) <case PARM_DECL>: - When processing_template_decl, check COMPLETE_TYPE_P before - calling is_really_empty_class. Don't check dependent_type_p. - -2020-07-08 Marek Polacek <polacek@redhat.com> - - PR c++/96103 - * parser.c (cp_parser_decltype): Print error about using decltype(auto) - in C++11. Check that the token following "auto" is ")". - -2020-07-07 Patrick Palka <ppalka@redhat.com> - - PR c++/95303 - * cxx-pretty-print.c (pp_cxx_unqualified_id): Check - PRIMARY_TEMPLATE_P before printing the innermost template - arguments. - -2020-07-07 Martin Sebor <msebor@redhat.com> - - PR c++/96063 - * parser.c (class_decl_loc_t::diag_mismatched_tags): Print notes only - if warning_at returns nonzero. - -2020-07-06 Martin Sebor <msebor@redhat.com> - - PR c++/95984 - * call.c (build_over_call): Check calls only when tf_warning is set. - -2020-07-06 Nathan Sidwell <nathan@acm.org> - - * decl.c (push_library_fn): Return the decl pushdecl_toplevel returns. - * except.c (verify_library_fn): Replace with ... - (declare_library_fn_1): ... this fn. Always push the fn. - (declare_library_fn): Call it. - (build_throw): Call declare_library_fn_1. - -2020-07-06 Jonathan Wakely <jwakely@redhat.com> - - PR c++/96068 - * parser.c (cp_parser_toplevel_declaration): Only do pedwarn for - empty-declaration in C++98. - -2020-07-02 Jason Merrill <jason@redhat.com> - Jakub Jelinek <jakub@redhat.com> - - * decl.c (grokfndecl): Allow consteval virtual. - * search.c (check_final_overrider): Check consteval mismatch. - * constexpr.c (cxx_eval_thunk_call): New. - (cxx_eval_call_expression): Call it. - * cvt.c (cp_get_fndecl_from_callee): Handle FDESC_EXPR. - * decl2.c (mark_vtable_entries): Track vtables with consteval. - (maybe_emit_vtables): Pass consteval_vtables through. - (clear_consteval_vfns): Replace consteval with nullptr. - (c_parse_final_cleanups): Call it. - -2020-07-01 Nathan Sidwell <nathan@acm.org> - - * class.c (copy_fndecl_with_name): Add additional predicate args, do - not deduce them locally. - (copy_operator_fn): Adjust copy_fndecl_with_name call. - (build_clone): Add vtt and inherited predicate args. Pass through - to copy_fndecl_with_name call. - (build_cdtor_clones): Likewise, pass through to build_clone as - needed. - (build_cdtor): Determine vtt and inherited here. - * cp-tree.h (DECL_NEEDS_CTT_PARM_P): Delete. - -2020-06-30 Nathan Sidwell <nathan@acm.org> - - * cp-tree.h (copy_fndecl_with_name): Rename to ... - (copy_operatorn_fn): ... this. Change arg type. - (clone_function_decl): Rename to ... - (clone_cdtor): ... this. - * class.c (copy_fndecl_with_name): Make static. - (copy_operator_fn): New wrapper. - (build_clones): Rename to ... - (build_cdtor_clones): ... this. - (clone_function_decl): Rename to ... - (clone_cdtor): ... this. Adjust build_clones calls. - (clone_constructors_and_destructors): Adjust clone_function_decl - calls. - * method.c (implicitly_declare_fn): Adjust copy_fndecl_with_name - call. - (lazily_declare_fn): Adjust clone_function_decl call. - * pt.c (tsubst_function_decl): Likewise. - (instantiate_template_1): Likewise. - -2020-06-30 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (morph_fn_to_coro): Remove trailing - space in a diagnostic. - -2020-06-30 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (expand_one_await_expression): Remove - code dealing with initial suspend. - (build_actor_fn): Remove code special-casing initial - and final suspend. Handle the final suspend and marking - of the coroutine as done. - (coro_rewrite_function_body): New. - (bind_expr_find_in_subtree): Remove. - (coro_body_contains_bind_expr_p): Remove. - (morph_fn_to_coro): Split the rewrite of the original - function into coro_rewrite_function_body and call it. - -2020-06-29 Marek Polacek <polacek@redhat.com> - - PR c++/94553 - * decl.c (duplicate_decls): Make sure a concept or a variable - template is unique in its declarative region. - -2020-06-29 Marek Polacek <polacek@redhat.com> - - PR c++/95568 - * pt.c (collect_ctor_idx_types): Use TREE_TYPE. - -2020-06-28 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95711 - * coroutines.cc (register_local_var_uses): Skip past - namespace decls. - -2020-06-27 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95736 - * coroutines.cc (get_awaitable_var): New helper. - (build_co_await): Check more carefully before - copying an awaitable. - (expand_one_await_expression): No initializer - is required when the awaitable is not a temp. - (register_awaits): Remove handling that is now - completed when the await expression is built. - -2020-06-27 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (morph_fn_to_coro): Diagnose unavailable - get_return_object_on_allocation_failure. - -2020-06-26 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95519 - * coroutines.cc (struct coroutine_info):Add a field - to hold computed p.return_void expressions. - (coro_build_promise_expression): New. - (get_coroutine_return_void_expr): New. - (finish_co_yield_expr): Build the promise expression - using coro_build_promise_expression. - (finish_co_return_stmt): Likewise. - (build_init_or_final_await): Likewise. - (morph_fn_to_coro): Likewise, for several cases. - -2020-06-26 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (morph_fn_to_coro): Handle error - returns in building g-r-o-o-a-f expressions. - -2020-06-24 Nicholas Krause <xerofoify@gmail.com> - - PR c++/95672 - * typeck2.c (cxx_incomplete_type_diagnostic): Add missing - TYPE_EXPANSION_PACK check for diagnosing incomplete types in - cxx_incomplete_type_diagnostic. - -2020-06-24 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95518 - PR c++/95813 - * coroutines.cc (act_des_fn): Copy function - attributes onto the outlined coroutine helpers. - -2020-06-24 Jason Merrill <jason@redhat.com> - - * call.c (build_over_call): Only call build_base_path once. - -2020-06-24 Jason Merrill <jason@redhat.com> - - PR c++/95719 - * call.c (build_over_call): Look up the overrider in base_binfo. - * class.c (lookup_vfn_in_binfo): Look through BINFO_PRIMARY_P. - -2020-06-23 Jason Merrill <jason@redhat.com> - - PR c++/93976 - Implement C++20 P2082R1, Fixing CTAD for aggregates. - * cp-tree.h (TPARMS_PRIMARY_TEMPLATE): Split out from... - (DECL_PRIMARY_TEMPLATE): ...here. - (builtin_guide_p): Declare. - * decl.c (reshape_init_class): Handle bases of a template. - (reshape_init_r): An array with dependent bound takes a single - initializer. - * pt.c (tsubst_default_argument): Shortcut {}. - (unify_pack_expansion): Allow omitted arguments to trailing pack. - (builtin_guide_p): New. - (collect_ctor_idx_types): Give a trailing pack a {} default - argument. Handle arrays better. - -2020-06-23 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95477 - * coroutines.cc (morph_fn_to_coro): Apply a cleanup to - the get return object when the DTOR is non-trivial. - -2020-06-20 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95505 - * coroutines.cc (morph_fn_to_coro): Update handling of - get-return-object-on-allocation-fail and diagnose missing - std::nothrow. - -2020-06-20 Jason Merrill <jason@redhat.com> - - * call.c (joust): Only compare constraints for non-template - candidates with matching parameters. - * pt.c (tsubst_pack_expansion): Fix getting a type parameter - pack. - (more_specialized_fn): Only compare constraints for candidates with - matching parameters. - -2020-06-19 Jason Merrill <jason@redhat.com> - - * method.c (early_check_defaulted_comparison): Allow defaulting - comparison outside class. Complain if non-member operator isn't a - friend. - -2020-06-18 Jason Merrill <jason@redhat.com> - - * method.c (early_check_defaulted_comparison): Check for &&. - (build_comparison_op): Allow empty union. Diagnose non-category - type. - (common_comparison_type): Remove handling for non-category type. - -2020-06-18 Marek Polacek <polacek@redhat.com> - - PR c++/95735 - * pt.c (finish_template_variable): Return if - coerce_innermost_template_parms return error_mark_node. - -2020-06-18 Marek Polacek <polacek@redhat.com> - - PR c++/95728 - * pt.c (tsubst_copy_and_build) <case NEW_EXPR>: Return error_mark_node - if placement is erroneous. - -2020-06-17 Jonathan Wakely <jwakely@redhat.com> - - PR c++/66159 - * parser.c (cp_parser_elaborated_type_specifier): Do not warn - unless in a declaration. - -2020-06-17 Jason Merrill <jason@redhat.com> - - * cp-tree.h (copy_fndecl_with_name): Declare. - * class.c (copy_fndecl_with_name): Split out from... - (build_clone): ...here. - (add_implicitly_declared_members): Add op== to TYPE_FIELDS. - * method.c (implicitly_declare_fn): Use copy_fndecl_with_name. - -2020-06-17 Jason Merrill <jason@redhat.com> - - * call.c (build_new_op_1): Don't look for a CALL_EXPR when - calling a consteval function. - -2020-06-17 Jason Merrill <jason@redhat.com> - - * decl2.c (grokfield): Pass SD_DEFAULTED and SD_DELETED. - * decl.c (duplicate_decls): Reduce error for delete - after earlier declaration to pedwarn. - -2020-06-17 Marek Polacek <polacek@redhat.com> - - PR c++/95508 - * constexpr.c (maybe_fold_non_dependent_expr): New. - * cp-tree.h (maybe_fold_non_dependent_expr): Declare. - * typeck.c (cp_build_array_ref): Call maybe_fold_non_dependent_expr - instead of maybe_constant_value. - -2020-06-16 Marek Polacek <polacek@redhat.com> - - PR c++/95369 - * call.c (add_list_candidates): Return if a designated initializer - is used with a non-aggregate. - (implicit_conversion_error): Give an error for the case above. - -2020-06-16 Marek Polacek <polacek@redhat.com> - - PR c++/95560 - * name-lookup.c (check_local_shadow): Check if types are - non-null before calling same_type_p. - -2020-06-16 Jakub Jelinek <jakub@redhat.com> - - * semantics.c (handle_omp_for_class_iterator): Adjust - c_omp_check_loop_iv_exprs caller. - (finish_omp_for): Likewise. Don't call fold_build_cleanup_point_expr - before calling c_finish_omp_for and c_omp_check_loop_iv, move it - after those calls. - * pt.c (tsubst_omp_for_iterator): Handle non-rectangular loops. - -2020-06-16 Jakub Jelinek <jakub@redhat.com> - - * parser.c (cp_parser_omp_clause_schedule): Reject modifier separated - from kind by comma rather than colon. - -2020-06-16 Patrick Palka <ppalka@redhat.com> - - * pt.c (perform_instantiation_time_access_checks): No need to - tsubst into decl. - * semantics.c (enforce_access): Verify that decl is not - dependent. - -2020-06-16 Patrick Palka <ppalka@redhat.com> - - PR c++/41437 - PR c++/47346 - * cp-tree.h (qualified_typedef_usage_s): Delete. - (qualified_typedef_usage_t): Delete. - (deferred_access_check): Move up in file. - (tree_template_info::typedefs_needing_access_checking): Delete. - (tree_template_info::deferred_access_checks): New field. - (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): Rename to ... - (TI_DEFERRED_ACCESS_CHECKS): ... this, and adjust accordingly. - * pt.c (perform_typedefs_access_check): Rename to ... - (perform_instantiation_time_access_checks): ... this, and adjust - accordingly. Remove unnecessary tree tests. - (instantiate_class_template_1): Adjust accordingly. - (instantiate_decl): Likewise. - * semantics.c (enforce_access): Likewise. - -2020-06-16 Patrick Palka <ppalka@redhat.com> - - PR c++/41437 - PR c++/47346 - * call.c (enforce_access): Move to semantics.c. - * cp-tree.h (enforce_access): Delete. - (get_types_needing_access_check): Delete. - (add_typedef_to_current_template_for_access_check): Delete. - * decl.c (make_typename_type): Adjust accordingly. Use - check_accessibility_of_qualified_id instead of directly using - perform_or_defer_access_check. - * parser.c (cp_parser_template_declaration_after_parameters): - Don't push a dk_no_check access state when parsing a template. - * pt.c (get_types_needing_access_check): Delete. - (append_type_to_template_for_access_check_1): Delete. - (perform_typedefs_access_check): Adjust. If type_decl is a - FIELD_DECL, also check its DECL_CONTEXT for dependence. Use - tsubst_copy instead of tsubst to substitute into type_decl so - that we substitute into the DECL_CONTEXT of a FIELD_DECL. - (append_type_to_template_for_access_check): Delete. - * search.c (accessible_p): Remove the processing_template_decl - early exit. - * semantics.c (enforce_access): Moved from call.c. If we're - parsing a template and the access check failed, add the check to - TI_TYPEDEFS_NEEDING_ACCESS_CHECKING. - (perform_or_defer_access_check): Adjust comment. - (add_typedef_to_current_template_for_access_check): Delete. - (check_accessibility_of_qualified_id): Adjust accordingly. - Exit early if the scope is dependent. - -2020-06-11 Patrick Palka <ppalka@redhat.com> - - PR c++/93467 - * constraint.cc (associate_classtype_constraints): If there is a - discrepancy between the current template depth and the template - depth of the original declaration, then adjust the template - parameter depth within the current constraints appropriately. - * pt.c (tsubst_friend_class): Substitute into and set the - constraints on the injected declaration. - -2020-06-11 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (instantiate_coro_traits): Pass a reference - to lambda closure objects to traits instantiation. - (morph_fn_to_coro): Likewise for promise parameter - preview and allocator lookup. - -2020-06-10 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95440 - * call.c (add_candidates): Use vec_safe_length() for - testing the arguments list. - (build_new_method_call_1): Use vec_safe_is_empty() when - checking for an empty args list. - -2020-06-10 Marek Polacek <polacek@redhat.com> - - PR c++/95562 - * parser.c (cp_parser_direct_declarator): Clear - CP_PARSER_FLAGS_DELAY_NOEXCEPT if the declarator kind is not - cdk_id. - -2020-06-09 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95137 - * coroutines.cc (expand_one_await_expression): Build separate - DTOR trees for the awaitable object on the destroy and resume - paths. - -2020-06-09 Jason Merrill <jason@redhat.com> - - PR c++/95552 - * cp-gimplify.c (predeclare_vla): Only predeclare a VLA if it's - wrapped in a pointer type. - -2020-06-05 Marek Polacek <polacek@redhat.com> - - PR c++/95369 - * call.c (build_converted_constant_expr_internal): Allow - list-initialization. - -2020-06-05 Iain Sandoe <iain@sandoe.co.uk> - - * cp-tree.def (CO_RETURN_EXPR): Correct the class - to use tcc_statement. - -2020-06-05 Jason Merrill <jason@redhat.com> - - * error.c (dump_binary_op): Handle negative operand to - POINTER_PLUS_EXPR. - -2020-06-04 Jason Merrill <jason@redhat.com> - - PR c++/93310 - * constexpr.c (cxx_eval_constant_expression) [OBJ_TYPE_REF]: - Evaluate OBJ_TYPE_REF_EXPR. - -2020-06-04 Jason Merrill <jason@redhat.com> - - PR c++/95158 - * class.c (lookup_vfn_in_binfo): New. - * call.c (build_over_call): Use it. - * cp-tree.h (resolves_to_fixed_type_p): Add default argument. - (lookup_vfn_in_binfo): Declare. - -2020-06-04 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95346 - * coroutines.cc (morph_fn_to_coro): Ensure that the get- - return-object is constructed correctly; When it is not the - final return value, pass it to the CTOR of the return type - as an rvalue, per the standard comment. - -2020-06-04 Jakub Jelinek <jakub@redhat.com> - - PR c++/82304 - PR c++/95307 - * constexpr.c (cxx_eval_constant_expression): Diagnose CONVERT_EXPR - conversions from pointer types to arithmetic types here... - (cxx_eval_outermost_constant_expr): ... instead of here. - -2020-06-03 Mark Wielaard <mark@klomp.org> - - * parser.c (cp_lexer_safe_previous_token): New function. - (cp_parser_error_1): Add name_hint if the previous token is - a string literal and next token is a CPP_NAME and we have a - missing header suggestion for the name. - -2020-06-03 Patrick Palka <ppalka@redhat.com> - - * pt.c (process_partial_specialization): Pass the full set of - generic template arguments to strictly_subsumes. - -2020-06-03 Patrick Palka <ppalka@redhat.com> - - PR c++/92103 - * pt.c (most_specialized_partial_spec): Reorganize the loop over - DECL_TEMPLATE_SPECIALIZATIONS. Check constraints_satisfied_p on - the original template declaration, not on the tsubsted one. - -2020-06-03 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95345 - * coroutines.cc (finish_co_await_expr): Revise to allow for - parameter packs. - (finish_co_yield_expr): Likewise. - -2020-06-03 Jason Merrill <jason@redhat.com> - - PR c++/95232 - * cp-tree.h (predeclare_vla): Declare. - * cp-gimplify.c (predeclare_vla): Handle getting a decl. - * pt.c (tsubst_expr) [DECL_EXPR]: Use it. - -2020-06-03 Tobias Burnus <tobias@codesourcery.com> - - * cp-gimplify.c (cxx_omp_predetermined_mapping): New. - * cp-objcp-common.h (LANG_HOOKS_OMP_PREDETERMINED_MAPPING): Redfine. - * cp-tree.h (cxx_omp_predetermined_mapping): Declare. - -2020-06-02 Jason Merrill <jason@redhat.com> - - PR c++/95193 - * pt.c (tsubst_decl): Relax assert. - -2020-06-02 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95050 - * coroutines.cc (build_co_await): Wrap the co_await expression - in a TARGET_EXPR, where needed. - (finish_co_yield_expr): Likewise. - -2020-06-02 Patrick Palka <ppalka@redhat.com> - - PR c++/92633 - PR c++/92838 - * pt.c (tsubst_function_decl): Don't do set_constraints when - regenerating a lambda. - (tsubst_lambda_expr): Substitute into the lambda's constraints - and do set_constraints here. - -2020-06-01 Jason Merrill <jason@redhat.com> - - PR c++/95466 - PR c++/95311 - PR c++/95221 - * class.c (build_vfn_ref): Revert 95311 change. - * cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): Build a - COMPOUND_EXPR. - -2020-06-01 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95350 - * coroutines.cc (struct param_info): Remove rv_ref field. - (build_actor_fn): Remove specifial rvalue ref handling. - (morph_fn_to_coro): Likewise. - -2020-05-31 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95087 - * coroutines.cc (morph_fn_to_coro): If we see an - early fatal error, drop the erroneous function body. - -2020-05-31 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (build_co_await): Remove unused - variable. - (finish_co_await_expr): Likewise. - (finish_co_yield_expr): Likewise; revise comment. - -2020-05-30 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (morph_fn_to_coro): Revise initialization - of the frame pointer to avoid an unused value. - -2020-05-30 Patrick Palka <ppalka@redhat.com> - - PR c++/95386 - * constraint.cc (satisfaction_value): Accept INTEGER_CST of any - boolean type. - -2020-05-29 Patrick Palka <ppalka@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/95181 - * class.c (add_method): Let special member function templates - coexist if they are not equivalently constrained, or in a class - template. - -2020-05-29 Jason Merrill <jason@redhat.com> - - PR c++/95371 - * pt.c (process_template_parm): Set DECL_TEMPLATE_INFO - on the DECL_TEMPLATE_RESULT. - -2020-05-29 Marek Polacek <polacek@redhat.com> - - PR c++/95344 - * cp-gimplify.c (cp_fold) <case MODIFY_EXPR>: Don't set - TREE_THIS_VOLATILE here. - (cp_fold): Set it here along with TREE_NO_WARNING. - -2020-05-29 Jason Merrill <jason@redhat.com> - - PR c++/95311 - PR c++/95221 - * class.c (build_vfn_ref): Don't fold the INDIRECT_REF. - -2020-05-29 Patrick Palka <ppalka@redhat.com> - - PR c++/92652 - PR c++/93698 - PR c++/94128 - * parser.c (cp_parser_requires_clause_expression): Temporarily - increment processing_template_decl only if it is 0. - (cp_parser_constraint_expression): Likewise. - (cp_parser_requires_expression): Likewise. - -2020-05-29 Patrick Palka <ppalka@redhat.com> - - PR c++/95241 - * constexpr.c (get_or_insert_ctor_field): Add limited support - for RANGE_EXPR index lookups. - -2020-05-28 Jakub Jelinek <jakub@redhat.com> - - PR c++/95328 - * decl.c (cp_finish_decomp): Call complete_type before checking - COMPLETE_TYPE_P. - -2020-05-28 Jason Merrill <jason@redhat.com> - - PR c++/94926 - * decl.c (cp_finish_decl): Revert r9-297 change. - (check_static_variable_definition): Likewise. - * constexpr.c (ensure_literal_type_for_constexpr_object): Likewise. - * pt.c (instantiate_decl): Return early on type error. - -2020-05-27 Jason Merrill <jason@redhat.com> - - PR c++/95319 - * decl.c (reshape_init_array_1): Don't reuse in overload context. - -2020-05-27 Jason Merrill <jason@redhat.com> - - PR c++/95242 - * call.c (build_new_op_1): Suppress - warn_zero_as_null_pointer_constant across comparison of <=> result - to 0. - -2020-05-27 Jason Merrill <jason@redhat.com> - - PR c++/95222 - * decl.c (grokdeclarator): Don't shift attributes in TYPENAME - context. - -2020-05-27 Nathan Sidwell <nathan@acm.org> - - PR c++/95263 - * pt.c (lookup_template_class_1): Restore alias template mutation. - -2020-05-26 Jakub Jelinek <jakub@redhat.com> - - PR c++/95197 - * cp-gimplify.c: Include omp-general.h. - (cp_genericize_r) <case OMP_DISTRIBUTE>: For class iteration - variables in composite distribute parallel for, instantiate copy - ctor of their types. - -2020-05-23 Patrick Palka <ppalka@redhat.com> - - PR c++/94038 - * constexpr.c (cxx_eval_constant_expression) - <case TEMPLATE_ID_EXPR>: Don't evaluate the concept when - constexpr evaluation is uid-sensitive. - -2020-05-22 Jason Merrill <jason@redhat.com> - - * cp-gimplify.c (cp_gimplify_expr) [CALL_EXPR]: Don't preevaluate - the function address if the call used operator syntax. - -2020-05-21 Jason Merrill <jason@redhat.com> - - PR c++/95221 - * cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): For a virtual - call, instrument the OBJ_TYPE_REF. - - * decl.c (compute_array_index_type_loc): Diagnose expressions - in a template that can't be constant. - * parser.c (cp_parser_direct_declarator): Don't check - non-constant array bounds here. - - * cp-tree.h (is_rvalue_constant_expression): Declare. - * constexpr.c (is_rvalue_constant_expression): New. - * parser.c (cp_parser_constant_expression): Use it. - * decl.c (cp_finish_decl): Try to treat a constexpr initializer in a - template as constant. - - * typeck.c (build_x_modify_expr): Handle error_mark_node arguments. - - * decl.c (grokparms): Return NULL_TREE if any parms were erroneous. - -2020-05-21 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (finish_co_return_stmt): Revert change to use - finish_expr_stmt. - -2020-05-21 Patrick Palka <ppalka@redhat.com> - - PR c++/94038 - * constexpr.c (constexpr_ctx::uid_sensitive): Remove field. - (uid_sensitive_constexpr_evaluation_value): Define. - (uid_sensitive_constexpr_evaluation_true_counter): Define. - (uid_sensitive_constexpr_evaluation_p): Define. - (uid_sensitive_constexpr_evaluation_sentinel): Define its - constructor. - (uid_sensitive_constexpr_evaluation_checker): Define its - constructor and its evaluation_restricted_p method. - (get_fundef_copy): Remove 'ctx' parameter. Use u_s_c_e_p - instead of constexpr_ctx::uid_sensitive. - (cxx_eval_call_expression): Use u_s_c_e_p instead, and test it - last. Adjust call to get_fundef_copy. - (instantiate_cx_fn_r): Test u_s_c_e_p so that we increment the - counter if necessary. - (cxx_eval_outermost_constant_expr): Remove 'uid_sensitive' - parameter. Adjust function body accordingly. - (maybe_constant_value): Remove 'uid_sensitive' parameter and - adjust function body accordingly. Set up a - uid_sensitive_constexpr_evaluation_checker, and use it to - conditionally update the cv_cache. - * cp-gimplify.c (cp_fold): Set up a - uid_sensitive_constexpr_evaluation_checker, and use it to - conditionally update the fold_cache. - * cp-tree.h (maybe_constant_value): Update declaration. - (struct uid_sensitive_constexpr_evaluation_sentinel): Define. - (struct sensitive_constexpr_evaluation_checker): Define. - * expr.c (fold_for_warn): Set up a - uid_sensitive_constexpr_evaluation_sentinel before calling - the folding subroutines. Drop all but the first argument to - maybe_constant_value. - -2020-05-20 Marek Polacek <polacek@redhat.com> - - DR 2237 - * parser.c (cp_parser_unqualified_id): Reject simple-template-id as - the declarator-id of a destructor. - (cp_parser_constructor_declarator_p): Reject simple-template-id as - the declarator-id of a constructor. - -2020-05-20 Marek Polacek <polacek@redhat.com> - - DR 2289 - PR c++/94553 - * cp-tree.h (SD_DECOMPOSITION): New flag. - * decl.c (duplicate_decls): Make sure a structured binding is unique - in its declarative region. - (start_decl): If INITIALIZED is SD_DECOMPOSITION, call - fit_decomposition_lang_decl. - (grokdeclarator): Compare INITIALIZED directly to SD_* flags. - * parser.c (cp_parser_decomposition_declaration): Pass SD_DECOMPOSITION - to start_decl. - -2020-05-20 Patrick Palka <ppalka@redhat.com> - - PR c++/95223 - * typeck.c (structural_comptypes): Don't perform - context-dependent resolution of TYPENAME_TYPEs when + * pt.c (comparing_dependent_aliases): New flag. + (template_args_equal, spec_hasher::equal): Set it. + (dependent_alias_template_spec_p): Assert that we don't + get non-types other than error_mark_node. + (instantiate_alias_template): SET_TYPE_STRUCTURAL_EQUALITY + on complex alias specializations. Set TYPE_DEPENDENT_P here. + (tsubst_decl): Not here. + * module.cc (module_state::read_cluster): Set + comparing_dependent_aliases instead of comparing_specializations. + * tree.c (cp_tree_equal): Remove comparing_specializations + module handling. + * typeck.c (structural_comptypes): Adjust. + (comptypes): Remove comparing_specializations handling. + +2021-01-29 Nathan Sidwell <nathan@acm.org> + + PR c++/98843 + * module.cc (module_state_config): Add num_entities field. + (module_state::read_entities): The entity_ary span is + already allocated. + (module_state::write_config): Write num_entities. + (module_state::read_config): Read num_entities. + (module_state::write): Set config's num_entities. + (module_state::read_initial): Allocate the entity ary + span here. + (module_state::read_language): Do not set entity_lwm + here. + +2021-01-29 Marek Polacek <polacek@redhat.com> + + PR c++/96137 + * parser.c (cp_parser_class_name): If parser->scope is + error_mark_node, return it, otherwise continue. + +2021-01-28 Jakub Jelinek <jakub@redhat.com> + + PR c++/98841 + * typeck.c (build_x_indirect_ref): For *this, return current_class_ref. + +2021-01-28 Jakub Jelinek <jakub@redhat.com> + + PR c++/33661 + PR c++/98847 + * decl.c (cp_finish_decl): For register vars with asmspec in templates + call set_user_assembler_name and set DECL_HARD_REGISTER. + * pt.c (tsubst_expr): When instantiating DECL_HARD_REGISTER vars, + pass asmspec_tree to cp_finish_decl. + +2021-01-28 Nathan Sidwell <nathan@acm.org> + + PR c++/98770 + * module.cc (trees_out::decl_value): Swap is_typedef & TYPE_NAME + check order. + (trees_in::decl_value): Do typedef frobbing only when installing + a new typedef, adjust is_matching_decl call. Swap is_typedef + & TYPE_NAME check. + (trees_in::is_matching_decl): Add is_typedef parm. Adjust variable + names and deal with typedef checking. + +2021-01-27 Jason Merrill <jason@redhat.com> + + PR c++/97874 + * name-lookup.c (lookup_using_decl): Clean up handling + of dependency and inherited constructors. + (finish_nonmember_using_decl): Handle DECL_DEPENDENT_P. + * pt.c (tsubst_expr): Handle DECL_DEPENDENT_P. + +2021-01-26 Jason Merrill <jason@redhat.com> + + PR c++/97474 + * call.c (type_passed_as): Don't mark invisiref restrict. + +2021-01-26 Jason Merrill <jason@redhat.com> + + PR c++/97566 + PR c++/98463 + * class.c (layout_class_type): An empty field gets size 0. + (is_empty_field): New. + (check_bases): Check it. + * cp-tree.h (is_empty_field): Declare it. + * constexpr.c (cxx_eval_store_expression): Check it. + (cx_check_missing_mem_inits): Likewise. + * init.c (perform_member_init): Likewise. + * typeck2.c (process_init_constructor_record): Likewise. + +2021-01-25 Martin Sebor <msebor@redhat.com> + + PR c++/98646 + * cvt.c (cp_fold_convert): Propagate TREE_NO_WARNING. + +2021-01-25 Jason Merrill <jason@redhat.com> + + PR c++/98463 + * constexpr.c (get_or_insert_ctor_field): Add check. + (cxx_eval_store_expression): Handle discontinuity of refs. + +2021-01-23 Anthony Sharp <anthonysharp15@gmail.com> + + * call.c (complain_about_access): Altered function. + * cp-tree.h (complain_about_access): Changed parameters of function. + (get_parent_with_private_access): Declared new function. + * search.c (get_parent_with_private_access): Defined new function. + * semantics.c (enforce_access): Modified function. + * typeck.c (complain_about_unrecognized_member): Updated function + arguments in complain_about_access. + +2021-01-23 Patrick Palka <ppalka@redhat.com> + + PR c++/97399 + * cp-tree.h (shared_member_p): Adjust declaration. + * parser.c (cp_parser_init_declarator): If the storage class + specifier is sc_static, pass true for static_p to + cp_parser_declarator. + (cp_parser_direct_declarator): Don't do inject_this_parm when + the declarator is a friend. + * search.c (shared_member_p): Change return type to bool and + adjust function body accordingly. Return false for a dependent + USING_DECL instead of aborting. + * semantics.c (finish_qualified_id_expr): Rely on shared_member_p + even when type-dependent. + +2021-01-22 Marek Polacek <polacek@redhat.com> + + PR c++/96623 + * parser.c (inject_parm_decls): Remove a redundant assignment. + (cp_parser_class_specifier_1): Clear current_class_{ptr,ref} + before calling inject_parm_decls. -2020-05-19 Nathan Sidwell <nathan@acm.org> - - * pt.c (lookup_template_class_1): Do not reinit template_info of an - alias here. - -2020-05-18 Martin Sebor <msebor@redhat.com> - - PR c++/94923 - * call.c ((maybe_warn_class_memaccess): Use is_byte_access_type. - * cp-tree.h (is_dummy_object): Return bool. - (is_byte_access_type): Declare new function. - * tree.c (is_dummy_object): Return bool. - (is_byte_access_type): Define new function. - -2020-05-19 Patrick Palka <ppalka@redhat.com> - - PR c++/87847 - * pt.c (init_template_processing): Enable sanitization for - decl_specializations and type_specializations. - - PR c++/66439 - * pt.c (fn_type_unification): Pass 'fn' instead of NULL_TREE as - the 'in_decl' parameter to coerce_template_parms. - -2020-05-18 Marek Polacek <polacek@redhat.com> - - PR c++/94955 - * typeck.c (cp_build_binary_op): Use fold_for_warn instead of - cp_fold_rvalue. - -2020-05-18 Marek Polacek <polacek@redhat.com> - - PR c++/94937 - * cvt.c (cp_get_fndecl_from_callee): Return NULL_TREE if the function - type is not INDIRECT_TYPE_P. - * decl.c (omp_declare_variant_finalize_one): Call - cp_get_callee_fndecl_nofold instead of looking for the function decl - manually. - -2020-05-18 Marek Polacek <polacek@redhat.com> - - PR c++/90915 - * parser.c (cp_parser_has_attribute_expression): Sorry on a - type-dependent argument. - -2020-05-18 Marek Polacek <polacek@redhat.com> - - DR 1512 - PR c++/87699 - * call.c (add_builtin_candidate) <case EQ_EXPR>: Create candidate - operator functions when type is std::nullptr_t for ==/!=. - * typeck.c (composite_pointer_type_r): Add a bool * parameter. Use it - to maybe add "const" to the pointer type. - (composite_pointer_type): Update the call to composite_pointer_type_r. - (cp_build_binary_op): Turn two warning_at into error_at. Print the - types. - -2020-05-18 Jason Merrill <jason@redhat.com> - - * call.c (build_over_call): Remove unnecessary - cp_stabilize_reference. - -2020-05-18 Marek Polacek <polacek@redhat.com> +2021-01-22 Jason Merrill <jason@redhat.com> - * call.c (add_builtin_candidate): Don't create a builtin overload - candidate for ++ when type is bool in C++17. + PR c++/98744 + * call.c (make_base_init_ok): Use DECL_HAS_VTT_PARM_P. -2020-05-18 Marek Polacek <polacek@redhat.com> +2021-01-22 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/95693 + * init.c (build_zero_init_1): Revert the 2018-03-06 change to + return build_zero_cst for reference types. + * typeck2.c (process_init_constructor_record): Instead call + build_zero_cst here during error recovery instead of build_zero_init. + +2021-01-22 Marek Polacek <polacek@redhat.com> + + PR c++/98545 + * mangle.c (write_member_name): Emit abi_warn_or_compat_version_crosses + warnings regardless of abi_version_at_least. + (write_expression): When the expression is a dependent name + and an operator name, write "on" before writing its name. + +2021-01-22 Marek Polacek <polacek@redhat.com> + + PR c++/97966 + * pt.c (instantiate_class_template_1): Instantiate members + marked with attribute used only after we're done instantiating + the class. - * cfns.h: Regenerated. +2021-01-21 Patrick Palka <ppalka@redhat.com> -2020-05-17 Iain Sandoe <iain@sandoe.co.uk> + PR c++/71879 + * semantics.c (finish_decltype_type): Set up a cp_unevaluated + sentinel at the start of the function. Remove a now-redundant + manual adjustment of cp_unevaluated_operand. + +2021-01-21 Nathan Sidwell <nathan@acm.org> - * coroutines.cc (morph_fn_to_coro): Initialize the gro variable. + PR c++/98624 + * module.cc (depset::hash::find_dependencies): Add + module arg. + (trees_out::core_vals): Check state before calling + write_location. + (sort_cluster, module_state::write): Adjust + find_dependencies call. + +2021-01-21 Jakub Jelinek <jakub@redhat.com> + + PR c++/98672 + * constexpr.c (check_for_return_continue_data): Add break_stmt member. + (check_for_return_continue): Also look for BREAK_STMT. Handle + SWITCH_STMT by ignoring break_stmt from its body. + (potential_constant_expression_1) <case FOR_STMT>, + <case WHILE_STMT>: If the condition isn't constant true, check if + the loop body can contain a return stmt. + <case SWITCH_STMT>: Adjust check_for_return_continue_data initializer. + <case IF_STMT>: If recursion with tf_none is successful, + merge *jump_target from the branches - returns with highest priority, + breaks or continues lower. If then branch is potentially constant and + doesn't return, check the else branch if it could return, break or + continue. -2020-05-16 Iain Sandoe <iain@sandoe.co.uk> +2021-01-21 Nathan Sidwell <nathan@acm.org> + + PR c++/98530 + * name-lookup.c (lookup_class_binding): Rearrange a stat-hack. + +2021-01-20 Nathan Sidwell <nathan@acm.org> - * coroutines.cc (finish_co_return_stmt): Implement rules - from [class.copy.elision] /3. + * module.cc (bytes_in::i, bytes_in::wi): Avoid left shift of + signed type. + +2021-01-20 Patrick Palka <ppalka@redhat.com> + + PR c++/95434 + * pt.c (tsubst) <case TEMPLATE_TYPE_PARM>: If tsubsting + CLASS_PLACEHOLDER_TEMPLATE yields a TEMPLATE_TEMPLATE_PARM, + adjust to its TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL. -2020-05-16 Patrick Palka <ppalka@redhat.com> +2021-01-20 Patrick Palka <ppalka@redhat.com> - PR c++/57943 - * semantics.c (finish_decltype_type): Call - instantiate_non_dependent_expr_sfinae on the expression. + PR c++/82613 + * parser.c (cp_parser_class_head): Defer access checking when + parsing the base-clause until all bases are seen and attached + to the class type. + * pt.c (instantiate_class_template): Likewise when substituting + into dependent bases. -2020-05-15 Patrick Palka <ppalka@redhat.com> +2021-01-20 Jakub Jelinek <jakub@redhat.com> - Revert: + PR c++/98742 + * semantics.c (finish_omp_clauses) <case OMP_CLAUSE_DETACH>: If + error_operand_p, remove clause without further checking. Check + for non-NULL TYPE_NAME. - 2020-04-07 Patrick Palka <ppalka@redhat.com> +2021-01-19 Marek Polacek <polacek@redhat.com> - PR c++/90996 - * typeck2.c (process_init_constructor_array): Propagate - CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to - the array initializer. - -2020-05-15 Jason Merrill <jason@redhat.com> - - PR c++/93286 - ICE with __is_constructible and variadic template. - * pt.c (tsubst_tree_list): New. - (tsubst, tsubst_copy_and_build): Use it. - * decl2.c (is_late_template_attribute): Handle error_mark_node args. - -2020-05-15 Nathan Sidwell <nathan@acm.org> - - * pt.c (template_args_equal): Fix thinkos in previous 'cleanup'. - -2020-05-14 Jason Merrill <jason@redhat.com> - - PR c++/93901 - * pt.c (maybe_instantiate_noexcept): Change clone handling. - -2020-05-14 Patrick Palka <ppalka@redhat.com> - - PR c++/78446 - * call.c (build_op_call): Pass complain to lookup_fnfields. - (build_special_member_call): Likewise. - * class.c (type_requires_array_cookie): Pass tf_warning_or_error - to lookup_fnfields. - * cp-tree.h (lookup_fnfields): Add tsubst_flags_t parameter. - * except.c (build_throw): Pass tf_warning_or_error to - lookup_fnfields. - * init.c (build_new_1): Pass complain to lookup_fnfields. - * method.c (locate_fn_flags): Likewise. - * name-lookup.c (lookup_name_real_1): Pass tf_warning_or_error - to lookup_fnfields. - * pt.c (tsubst_baselink): Pass complain to lookup_fnfields. - * search.c (lookup_fnfields): New 'complain' parameter. Pass it - to lookup_member. - -2020-05-14 Nathan Sidwell <nathan@acm.org> - - * parser.c (cp_parser_diagnose_invalid_typename): Mention - std=c++20 not 2a, reformat dependent binfo inform loops. - - * pt.c (tsubst_template_decl): Reorder and commonize some control - paths. - - * pt.c (tsubst_friend_function): Simplify control flow. - - * pt.c (lookup_template_class_1): Remove unnecessary else by - simply grabbing TYPE_NAME earlier. - - * pt.c (push_template_decl_real): Adjust friend pushing logic. - Reinit template type. - - * pt.c (build_template_decl): Init DECL_TEMPLATE_RESULT & - TREE_TYPE here ... - (process_partial_specialization): ... not here ... - (push_template_decl_real, add_inherited_template_parms) - (build_deduction_guide): ... or here. - -2020-05-14 Jakub Jelinek <jakub@redhat.com> - - * cp-gimplify.c (cp_genericize_r): Set cfun->has_omp_target. - -2020-05-13 Patrick Palka <ppalka@redhat.com> - - PR c++/79706 - * init.c (build_vec_delete_1): Just return error_mark_node if - deallocate_expr is error_mark_node. - (build_delete): Just return error_mark_node if do_delete is + PR c++/98659 + * pt.c (maybe_instantiate_noexcept): Return false if FN is error_mark_node. -2020-05-13 Patrick Palka <ppalka@redhat.com> - - PR c++/95020 - * constraint.cc (tsubst_requires_expr): Produce a new - requires-expression when processing_template_decl, even if - template arguments are not dependent. - -2020-05-13 Marek Polacek <polacek@redhat.com> - - PR c++/95066 - * decl.c (duplicate_decls): Set DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P. - -2020-05-13 Nathan Sidwell <nathan@acm.org> - - * pt.c (template_args_equal): Reorder category checking for - clarity. - - * pt.c (perform_typedefs_access_check): Cache expensively - calculated object references. - (check_auto_in_tmpl_args): Just assert we do not get unexpected - nodes, rather than silently do nothing. - (append_type_to_template_for_access): Likewise, cache expensie - object reference. - - * pt.c (canonical_type_parameter): Simplify. - - Formatting fixups & some simplifications. - * pt.c (spec_hash_table): New typedef. - (decl_specializations, type_specializations): Use it. - (retrieve_specialization): Likewise. - (register_specialization): Remove unnecessary casts. - (push_template_decl_real): Reformat. - (instantiate_class_template_1): Use more RAII. - (make_argument_pack): Simplify. - (instantiate_template_1): Use gcc_checking_assert for expensive - asserts. - (instantiate_decl): Likewise. - (resolve_typename_type): Reformat comment. - * semantics.c (struct deferred_access): Remove unnecessary GTY on - member. - (begin_class_definition): Fix formatting. - -2020-05-13 Jason Merrill <jason@redhat.com> - - * call.c, class.c, constexpr.c, constraint.cc, decl.c, init.c, - lambda.c, lex.c, method.c, name-lookup.c, parser.c, pt.c, tree.c, - typeck2.c: Change cxx2a to cxx20. - -2020-05-12 Marek Polacek <polacek@redhat.com> - - PR c++/95074 - * parser.c (cp_parser_postfix_expression) <case CPP_OPEN_PAREN>: When - looking for a block-scope function declaration, look through the whole - set, not just the first function in the overload set. - -2020-05-12 Jakub Jelinek <jakub@redhat.com> - - PR c++/95063 - * pt.c (tsubst_decl): Deal with DECL_OMP_PRIVATIZED_MEMBER for - a bit-field. - -2020-05-11 Jason Merrill <jason@redhat.com> - - Resolve C++20 NB comment CA104 - * pt.c (determine_specialization): Compare constraints for - specialization of member template of class instantiation. - -2020-05-11 Jason Merrill <jason@redhat.com> - - PR c++/92583 - PR c++/92654 - * tree.c (cp_walk_subtrees): Stop at typedefs. - Handle TYPENAME_TYPE here. - * pt.c (find_parameter_packs_r): Not here. - (for_each_template_parm_r): Clear *walk_subtrees. - * decl2.c (min_vis_r): Look through typedefs. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * call.c (implicit_conversion_error): Split out from... - (perform_implicit_conversion_flags): ...here. - (build_converted_constant_expr_internal): Use it. - -2020-05-11 Jason Merrill <jason@redhat.com> - - PR c++/90748 - * parser.c (inject_parm_decls): Set current_class_ptr here. - (cp_parser_direct_declarator): And here. - (cp_parser_late_return_type_opt): Not here. - (cp_parser_noexcept_specification_opt): Nor here. - (cp_parser_exception_specification_opt) - (cp_parser_late_noexcept_specifier): Remove unneeded parameters. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * decl.c (cxx_init_decl_processing): Call declare_weak for - __cxa_pure_virtual. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * pt.c (instantiate_class_template_1): Call tsubst_expr for - STATIC_ASSERT member. - * ptree.c (cxx_print_xnode): Handle STATIC_ASSERT. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * pt.c (find_parameter_packs_r) [LAMBDA_EXPR]: Remove redundant - walking of capture list. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * cp-tree.h (LOOKUP_EXPLICIT_TMPL_ARGS): Remove. - * call.c (build_new_function_call): Don't set it. - (build_new_method_call_1): Likewise. - (build_over_call): Check cand->explicit_targs instead. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * decl.c (compute_array_index_type_loc): Stabilize before building - the MINUS_EXPR. - -2020-05-11 Jason Merrill <jason@redhat.com> - - * decl.c (grokdeclarator): Adjust deprecated_state here. - (start_decl): Not here. - -2020-05-08 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/95003 - * coroutines.cc (build_actor_fn): Ensure that bind scopes - are marked as having side-effects where necessary. - (replace_statement_captures): Likewise. - (morph_fn_to_coro): Likewise. - -2020-05-08 Nathan Sidwell <nathan@acm.org> - - * NEWS: Delete, it is so stale. - - * parser.c (cp_lexer_set_source_position_from_token): EOF has a - location too. - -2020-05-07 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94817 - PR c++/94829 - * coroutines.cc (morph_fn_to_coro): Set unformed outline - functions to error_mark_node. For early error returns suppress - warnings about missing ramp return values. Fix reinstatement - of the function body on pre-existing initial error. - * decl.c (finish_function): Use the normal error path for fails - in the ramp function, do not try to compile the helpers if the - transform fails. - -2020-05-07 Marek Polacek <polacek@redhat.com> - - PR c++/94590 - Detect long double -> double narrowing. - * typeck2.c (check_narrowing): Detect long double -> double - narrowing even when double and long double have the same - precision. Make it handle conversions to float too. - -2020-05-07 Marek Polacek <polacek@redhat.com> - - PR c++/94255 - * parser.c (cp_parser_class_specifier_1): Check that the scope is - nested inside current scope before pushing it. - -2020-05-07 Marek Polacek <polacek@redhat.com> - - P1957R2 - * typeck2.c (check_narrowing): Consider T* to bool narrowing - in C++11 and up. - -2020-05-07 Marek Polacek <polacek@redhat.com> - - * decl.c (grok_op_properties): Fix spelling of non-static. - * typeck.c (build_class_member_access_expr): Likewise. - -2020-05-07 Richard Biener <rguenther@suse.de> - - PR middle-end/94703 - * optimize.c (update_cloned_parm): Copy DECL_NOT_GIMPLE_REG_P. - -2020-05-06 Marek Polacek <polacek@redhat.com> - - PR c++/94938 - * pt.c (tsubst_copy_and_build): Call type_dependent_expression_p_push - instead of uses_template_parms. Move the warning_sentinels after the - RECURs. - -2020-05-06 Jakub Jelinek <jakub@redhat.com> - - PR c++/94951 - * typeck.c (cp_strict_aliasing_warning): New function. - (cp_build_indirect_ref_1, build_reinterpret_cast_1): Use - it instead of strict_aliasing_warning. - - PR c++/94907 - * method.c (defaulted_late_check): Don't call synthesize_method - on constexpr sfk_comparison if it has been called on it already. - -2020-05-06 Nathan Sidwell <nathan@acm.org> - - PR c++/94946 - * decl.c (grokdeclarator): Don't splice template attributes in - parm context -- they can apply to the parm. - -2020-05-05 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc: Remove references to n4849 throughout. - -2020-05-05 Jason Merrill <jason@redhat.com> - - CWG 2235 - * pt.c (more_specialized_fn): Do consider parms with no deducible - template parameters. - -2020-05-05 Jason Merrill <jason@redhat.com> - - PR c++/90212 - * constexpr.c (potential_constant_expression_1): In a lambda - function, consider a captured variable directly. - -2020-05-05 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (transform_await_wrapper): Check that we have - no unlowered co_yields. - (captures_temporary): Likewise. - (register_awaits): Likewise. - -2020-05-05 Nathan Sidwell <nathan@acm.org> - - PR c++/94807 - * coroutines.cc (morph_fn_to_coro): Just check for - closure_identifier. - * pt.c (tsubst_function_decl): Update lambda fn's this_ptr name. - -2020-05-05 Marek Polacek <polacek@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/94799 - * parser.c (cp_parser_postfix_dot_deref_expression): If we have - a type-dependent object of class type, stash it to - parser->context->object_type. If the postfix expression doesn't have - a type, use typeof. - (cp_parser_class_name): Consider object scope too. - (cp_parser_lookup_name): Remove code dealing with the case when - object_type is unknown_type_node. - -2020-05-04 Patrick Palka <ppalka@redhat.com> - - PR c++/94038 - * cp-gimplify.c (cp_fold) <case CALL_EXPR>: Move some variable - declarations closer to their uses. Copy the CALL_EXPR only - when one of its arguments has changed. - <case TREE_VEC>: Instead of first collecting the folded - arguments into a releasing_vec, just make a copy of the TREE_VEC - as soon as folding changes one of its arguments. - -2020-05-04 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (morph_fn_to_coro): Mark the coro.gro variable - as artificial and ignored. - -2020-05-04 Nathan Sidwell <nathan@acm.org> - - pt.c (process_template_parm): Don't walk the template list twice, - remember the final node instead. - (end_template_parm_list): Refactor. Comment on why we do a pop - and a push. - - PR c++/94827 -- don't save parms in nested requirement - * constraint.cc (tsubst_nested_requirement): TYPE directly holds - notmalized requirement. - (finish_nested_requirement): Don't stash current tpl parms into - the requirement. - (diagnose_nested_requirement): TYPE directly holds notmalized - requirement. - -2020-05-01 Patrick Palka <ppalka@redhat.com> - - PR c++/90880 - * cp-tree.h (check_accessibility_of_qualified_id): Add - tsubst_flags_t parameter and change return type to bool. - * parser.c (cp_parser_lookup_name): Pass tf_warning_to_error to - check_accessibility_of_qualified_id. - * pt.c (tsubst_qualified_id): Return error_mark_node if - check_accessibility_of_qualified_id returns false. - * semantics.c (check_accessibility_of_qualified_id): Add - complain parameter. Pass complain instead of - tf_warning_or_error to perform_or_defer_access_check. Return - true unless perform_or_defer_access_check returns false. - -2020-05-01 Marek Polacek <polacek@redhat.com> - - PR c++/94885 - * typeck2.c (process_init_constructor_record): Return PICFLAG_ERRONEOUS - if an initializer element was erroneous. - -2020-05-01 Jason Merrill <jason@redhat.com> - - PR c++/90479 - * init.c (get_nsdmi): Don't push_to_top_level for a local class. - -2020-05-01 Jason Merrill <jason@redhat.com> - - PR c++/91529 - * decl.c (cp_finish_decl): Also clear TREE_READONLY if - -fmerge-all-constants. - -2020-05-01 Jason Merrill <jason@redhat.com> - - PR c++/93822 - * pt.c (tsubst_decl): Make sure DECL_VALUE_EXPR continues to have - the same type as the variable. - -2020-04-30 Jason Merrill <jason@redhat.com> - Nathan Sidwell <nathan@acm.org> - - PR c++/94827 - * constraint.cc (map_arguments): If ARGS is null, it's a - self-mapping of parms. - (finish_nested_requirement): Do not pass argified - current_template_parms to normalization. - (tsubst_nested_requirement): Don't assert no template parms. - -2020-04-30 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94886 - * coroutines.cc (transform_local_var_uses): Defer walking - the DECL_INITIALs of BIND_EXPR vars until all the frame - allocations have been made. - -2020-04-30 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94883 - * coroutines.cc (register_awaits): Update target - expressions for awaitable and suspend handle - initializers. - -2020-04-30 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94879 - * coroutines.cc (build_co_await): Account for variables - with DECL_VALUE_EXPRs. - (captures_temporary): Likewise. - (register_awaits): Likewise. - -2020-04-29 Patrick Palka <ppalka@redhat.com> - - PR c++/94830 - * pt.c (find_template_parameter_info::parm_list): New field. - (keep_template_parm): Use the new field to build up the - parameter list here instead of ... - (find_template_parameters): ... here. Return ftpi.parm_list. - -2020-04-29 Jakub Jelinek <jakub@redhat.com> - - PR target/94707 - * class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty - base artificial FIELD_DECLs. - (layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class - field_poverlapping_p FIELD_DECLs. - -2020-04-29 Patrick Palka <ppalka@redhat.com> - - PR c++/94819 - * constraint.cc (satisfy_declaration_constraints): Use saved_t - instead of t as the key to decl_satisfied_cache. - - PR c++/94808 - * error.c (print_requires_expression_info): Print the dependent - form of the parameter list with its template parameter mapping, - rather than printing the substituted form. - -2020-04-28 Jason Merrill <jason@redhat.com> - - PR c++/94583 - * decl.c (use_eh_spec_block): Check nothrow type after - DECL_DEFAULTED_FN. - * pt.c (maybe_instantiate_noexcept): Call synthesize_method for - DECL_MAYBE_DELETED fns here. - * decl2.c (mark_used): Not here. - * method.c (get_defaulted_eh_spec): Reject DECL_MAYBE_DELETED here. - -2020-04-28 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94760 - * coroutines.cc (instantiate_coro_traits): Pass a reference to - object type rather than a pointer type for 'this', for method - coroutines. - (struct param_info): Add a field to hold that the parm is a lambda - closure pointer. - (morph_fn_to_coro): Check for lambda closure pointers in the - args. Use a reference to *this when building the args list for the - promise allocator lookup. - -2020-04-28 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94759 - * coroutines.cc (coro_promise_type_found_p): Do not - exclude non-classes here (this needs to be handled in the - coroutine header). - (morph_fn_to_coro): Allow for the case where the coroutine - returns void. - -2020-04-27 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94701 - * coroutines.cc (struct local_var_info): Add fields for static - variables and those with DECL_VALUE_EXPR redirection. - (transform_local_var_uses): Skip past typedefs and static vars - and then account for redirected variables. - (register_local_var_uses): Likewise. - -2020-04-27 Jason Merrill <jason@redhat.com> - - PR c++/90750 - PR c++/79585 - * decl.c (grokdeclarator): Move dependent attribute to decl. - * decl2.c (splice_template_attributes): No longer static. - -2020-04-27 Patrick Palka <ppalka@redhat.com> - - PR c++/94772 - * constexpr.c (cxx_eval_call_expression): Don't set new_obj if we're - evaluating the target constructor of a delegating constructor. - (cxx_eval_store_expression): Don't set TREE_READONLY if the LHS of the - INIT_EXPR is '*this'. - -2020-04-26 Marek Polacek <polacek@redhat.com> - - PR c++/90320 - * call.c (struct conversion): Add copy_init_p. - (standard_conversion): Set copy_init_p in ck_base and ck_rvalue - if FLAGS demands LOOKUP_ONLYCONVERTING. - (convert_like_real) <case ck_base>: If copy_init_p is set, or - LOOKUP_ONLYCONVERTING into FLAGS. - -2020-04-26 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94752 - * coroutines.cc (morph_fn_to_coro): Ensure that - unnamed function params have a usable and distinct - frame field name. - -2020-04-24 Jason Merrill <jason@redhat.com> - - PR c++/94583 - * decl.c (redeclaration_error_message): Reject defaulted comparison - operator that has been previously declared. - -2020-04-25 Patrick Palka <ppalka@redhat.com> - - * parser.c (cp_parser_diagnose_invalid_type_name): Suggest enabling - concepts if the invalid identifier is 'requires'. - -2020-04-25 Jakub Jelinek <jakub@redhat.com> - - PR c++/94742 - * semantics.c (finish_call_expr): When looking if all overloads - are noreturn, use STRIP_TEMPLATE to look through TEMPLATE_DECLs. - -2020-04-24 Martin Liska <mliska@suse.cz> - - * coroutines.cc: Fix compilation error for release checking - where we miss declaration of ‘coro_body_contains_bind_expr_p’. - -2020-04-23 Patrick Palka <ppalka@redhat.com> - - * tree.c (zero_init_expr_p): Use uses_template_parms instead of - dependent_type_p. - - PR c++/94645 - * pt.c (template_class_depth): Walk into the DECL_FRIEND_CONTEXT of a - friend declaration rather than into its CP_DECL_CONTEXT. - -2020-04-23 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94288 - * coroutines.cc (await_statement_expander): Simplify cases. - (struct susp_frame_data): Add fields for truth and/or if - cases, rename one field. - (analyze_expression_awaits): New. - (expand_one_truth_if): New. - (add_var_to_bind): New helper. - (coro_build_add_if_not_cond_break): New helper. - (await_statement_walker): Handle conditional expressions, - handle expansion of truth-and/or-if cases. - (bind_expr_find_in_subtree): New, checking-only. - (coro_body_contains_bind_expr_p): New, checking-only. - (morph_fn_to_coro): Ensure that we have a top level bind - expression. - -2020-04-22 Jonathan Wakely <jwakely@redhat.com> - - PR translation/94698 - * class.c (check_field_decls): Change "define" to "declare" in - -Weffc++ diagnostics. - -2020-04-22 Patrick Palka <ppalka@redhat.com> - - PR c++/94719 - PR c++/94549 - * constraint.cc (satisfy_declaration_constraints): If the inherited - constructor points to an instantiation of a constructor template, - remember and use its attached template arguments. - -2020-04-22 Jonathan Wakely <jwakely@redhat.com> - - PR translation/94698 - * class.c (check_field_decls): Change "override" to "define" in - -Weffc++ diagnostics. - -2020-04-22 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94682 - * coroutines.cc (struct param_info): Add a field to note that - the param is 'this'. - (morph_fn_to_coro): Convert this to a reference before using it - in the promise parameter preview. - -2020-04-22 Jason Merrill <jason@redhat.com> - - PR c++/94546 - * pt.c (register_parameter_specializations): If the instantiation is - still a parameter pack, don't wrap it in a NONTYPE_ARGUMENT_PACK. - (tsubst_pack_expansion, tsubst_expr): Adjust. - -2020-04-22 Martin Sebor <msebor@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/94510 - * decl.c (reshape_init_array_1): Avoid stripping redundant trailing - zero initializers... - * mangle.c (write_expression): ...and handle them here even for - pointers to members by calling zero_init_expr_p. - * cp-tree.h (zero_init_expr_p): Declare. - * tree.c (zero_init_expr_p): Define. - (type_initializer_zero_p): Remove. - * pt.c (tparm_obj_values): New hash_map. - (get_template_parm_object): Store to it. - (tparm_object_argument): New. - -2020-04-22 Patrick Palka <ppalka@redhat.com> - - PR c++/67825 - * constraint.cc (diagnose_valid_expression): Check convert_to_void here - as well as in tsubst_valid_expression_requirement. - -2020-04-21 Patrick Palka <ppalka@redhat.com> - - PR c++/94549 - * constraint.cc (satisfy_declaration_constraints): Don't strip the - inherited constructor if it already has template information. - - PR c++/94597 - * pt.c (any_template_parm_r) <case IDENTIFIER_NODE>: New case. If this - is a conversion operator, visit its TREE_TYPE. - -2020-04-21 Nathan Sidwell <nathan@acm.org> - - * pt.c (tsubst_copy_and_build) [POINTER_PLUS_EXPR]: Check for - error_mark_node. - -2020-04-21 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94661 - * coroutines.cc (morph_fn_to_coro): Simplify return - value computation. - -2020-04-17 Marek Polacek <polacek@redhat.com> - - PR c++/94592 - * constexpr.c (cxx_eval_outermost_constant_expr): Return when T is - a BRACE_ENCLOSED_INITIALIZER_P. - (is_nondependent_constant_expression): Don't check - BRACE_ENCLOSED_INITIALIZER_P. - (is_nondependent_static_init_expression): Likewise. - -2020-04-20 Patrick Palka <ppalka@redhat.com> - - PR c++/94628 - * cp-tree.h (lss_policy::lss_nop): New enumerator. - * pt.c (local_specialization_stack::local_specialization_stack): Handle - an lss_nop policy. - (local_specialization_stack::~local_specialization_stack): Likewise. - (tsubst_pack_expansion): Use a local_specialization_stack instead of - manually saving and restoring local_specializations. Conditionally - replace local_specializations sooner, before the handling of the - unsubstituted_packs case. - -2020-04-20 Marek Polacek <polacek@redhat.com> - - PR c++/94505 - bogus -Wparentheses warning with fold-expression. - * pt.c (fold_expression): Add warning_sentinel for -Wparentheses - before calling build_x_binary_op. - -2020-04-20 Marek Polacek <polacek@redhat.com> - - * coroutines.cc (captures_temporary): Don't assign the result of - STRIP_NOPS to the same variable. - -2020-04-20 Nathan Sidwell <nathan@acm.org> - - PR c++/94454 - tpl-tpl-parms are not canonicalizable types - * pt.c (canonical_type_parameter): Assert not a tpl-tpl-parm. - (process_template_parm): tpl-tpl-parms are structural. - (rewrite_template_parm): Propagate structuralness. - - PR c++/94454 - Expr pack expansion equality - * tree.c (cp_tree_equal) [TEMPLATE_ID_EXPR, default]: Refactor. - [EXPR_PACK_EXPANSION]: Add. - - PR c++/94454 Template Argument Hashing - * pt.c (iterative_hash_template_arg): Strip nodes as - template_args_equal does. - [ARGUMENT_PACK_SELECT, TREE_VEC, CONSTRUCTOR]: Refactor. - [node_class:TEMPLATE_TEMPLATE_PARM]: Hash by level & index. - [node_class:default]: Refactor. - -2020-04-18 Patrick Palka <ppalka@redhat.com> - - PR c++/94632 - * tree.c (cp_tree_equal) <case PARM_DECL>: Ignore - comparing_specializations if the parameters' contexts are identical. - - PR c++/92187 - * pt.c (splice_late_return_type): Propagate cv-qualifiers and - PLACEHOLDER_TYPE_CONSTRAINTS from the original auto node to the new one. - -2020-04-17 Patrick Palka <ppalka@redhat.com> - - PR c++/94483 - * lambda.c (lambda_capture_field_type): Avoid doing auto deduction if - the explicit initializer has parameter packs. - - PR c++/88754 - * parser.c (cp_parser_check_template_parameters): Before issuing a hard - error, first try simulating an error instead. - -2020-04-17 Jakub Jelinek <jakub@redhat.com> - - PR other/94629 - * call.c (build_conditional_expr_1): Remove redundant assignment to - arg2. - -2020-04-16 Patrick Palka <ppalka@redhat.com> - - PR c++/94475 - * cvt.c (ocp_convert): If the result of scalar_constant_value is - erroneous, ignore it and use the original expression. - -2020-04-16 Jakub Jelinek <jakub@redhat.com> - - PR c++/94571 - * parser.c (cp_parser_simple_declaration): Fix up a pasto in - diagnostics. - -2020-04-15 Jakub Jelinek <jakub@redhat.com> - - PR c/94593 - * parser.c (cp_parser_pragma) <case PRAGMA_OMP_REQUIRES>: Reject - requires directive when not at file or namespace scope. - -2020-04-14 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94359 - * coroutines.cc (build_actor_fn): Check that the target can - support the resume tailcall before mandating it. - -2020-04-14 Patrick Palka <ppalka@redhat.com> - - PR c++/85278 - * cxx-pretty-print.c (cxx_pretty_printer:simple_type_specifier) - <case DECLTYPE_TYPE>: Handle DECLTYPE_TYPE here instead of ... - (pp_cxx_type_specifier_seq) <case DECLTYPE_TYPE>: ... here. - (cxx_pretty_printer::direct_abstract_declarator) <case DECLTYPE_TYPE>: - New no-op case. - - PR c++/94034 - * constexpr.c (replace_result_decl_data): New struct. - (replace_result_decl_data_r): New function. - (replace_result_decl): New function. - (cxx_eval_call_expression): Use it. - * tree.c (build_aggr_init_expr): Set the location of the AGGR_INIT_EXPR - to that of its initializer. - -2020-04-13 Marek Polacek <polacek@redhat.com> - - PR c++/94588 - * name-lookup.c (check_local_shadow): Add an inform call. - -2020-04-13 Patrick Palka <ppalka@redhat.com> - - PR c++/94521 - * error.c (dump_scope): Pass TFF_NO_FUNCTION_ARGUMENTS to - dump_function_decl when printing a function template instantiation as a - scope. - - PR c++/94470 - * constexpr.c (get_or_insert_ctor_field): Set default value of parameter - 'pos_hint' to -1. - (cxx_eval_bare_aggregate): Use get_or_insert_ctor_field instead of - assuming the the next index belongs at the end of the new CONSTRUCTOR. - (cxx_eval_store_expression): Revert PR c++/78572 fix. - -2020-04-13 Nathan Sidwell <nathan@acm.org> - - PR c++/94426 lambdas with internal linkage are different to no-linkage - * decl2.c (determine_visibility): A lambda's visibility is - affected by its extra scope. - * pt.c (instantiate_decl): Determine var's visibility before - instantiating its initializer. - * tree.c (no_linkage_check): Revert code looking at visibility of - lambda's extra scope. -` -2020-04-10 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94528 - * coroutines.cc (co_await_expander): Remove. - (expand_one_await_expression): New. - (process_one_statement): New. - (await_statement_expander): New. - (build_actor_fn): Revise to use per-statement expander. - (struct susp_frame_data): Reorder and comment. - (register_awaits): Factor code. - (replace_statement_captures): New, factored from... - (maybe_promote_captured_temps):.. here. - (await_statement_walker): Revise to process per statement. - (morph_fn_to_coro): Use revised susp_frame_data layout. - -2020-04-10 Marek Polacek <polacek@redhat.com> - - PR c++/94149 - * method.c (constructible_expr): In C++20, try using parenthesized - initialization of aggregates to determine the result of - __is_constructible. - -2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (co_await_expander): Simplify. - -2020-04-09 Jason Merrill <jason@redhat.com> - - PR c++/94523 - * constexpr.c (cxx_eval_constant_expression) [VAR_DECL]: Look at - ctx->object and ctx->global->values first. - -2020-04-09 Marek Polacek <polacek@redhat.com> - - PR c++/93790 - * call.c (initialize_reference): If the reference binding failed, maybe - try initializing from { }. - * decl.c (grok_reference_init): For T& t(e), set - LOOKUP_AGGREGATE_PAREN_INIT but don't build up a constructor yet. - -2020-04-08 Iain Sandoe <iain@sandoe.co.uk> - Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (maybe_promote_captured_temps): Add a cleanup - expression, if needed, to any call from which we promoted - temporaries captured by reference. - -2020-04-08 Marek Polacek <polacek@redhat.com> - - PR c++/94507 - ICE-on-invalid with lambda template. - * pt.c (tsubst_lambda_expr): Cope when tsubst_template_decl or - tsubst_function_decl returns error_mark_node. - -2020-04-08 Martin Liska <mliska@suse.cz> - - PR c++/94314 - * decl.c (duplicate_decls): Duplicate also DECL_IS_REPLACEABLE_OPERATOR. - (cxx_init_decl_processing): Mark replaceable all implicitly defined - operators. - -2020-04-08 Patrick Palka <ppalka@redhat.com> - - Core issues 1001 and 1322 - PR c++/92010 - * pt.c (rebuild_function_or_method_type): Split function out from ... - (tsubst_function_type): ... here. - (maybe_rebuild_function_decl_type): New function. - (tsubst_function_decl): Use it. - -2020-04-08 Jakub Jelinek <jakub@redhat.com> - - PR c++/94325 - * decl.c (begin_destructor_body): For CLASSTYPE_VBASECLASSES class - dtors, if CLASSTYPE_PRIMARY_BINFO is non-NULL, but not BINFO_VIRTUAL_P, - look at CLASSTYPE_PRIMARY_BINFO of its BINFO_TYPE if it is not - BINFO_VIRTUAL_P, and so on. - -2020-04-08 Marek Polacek <polacek@redhat.com> - - PR c++/94478 - ICE with defaulted comparison operator - * method.c (early_check_defaulted_comparison): Give an error when the - context is null. - -2020-04-08 Tobias Burnus <tobias@codesourcery.com> - - PR middle-end/94120 - * paser.c (cp_parser_oacc_declare): Add check that variables - are declared in the same scope as the directive. - -2020-04-07 Jason Merrill <jason@redhat.com> - - PR c++/94480 - * parser.c (cp_parser_requires_expression): Use tentative_firewall. - - PR c++/94481 - * parser.c (cp_parser_placeholder_type_specifier): Use - matching_parens. - -2020-04-07 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (maybe_promote_captured_temps): Ensure that - reference capture placeholder vars are properly declared. +2021-01-19 Marek Polacek <polacek@redhat.com> -2020-04-07 Patrick Palka <ppalka@redhat.com> + PR c++/98687 + * name-lookup.c (push_using_decl_bindings): New, broken out of... + (finish_nonmember_using_decl): ...here. + * name-lookup.h (push_using_decl_bindings): Update declaration. + * pt.c (tsubst_expr): Update the call to push_using_decl_bindings. - PR c++/90996 - * tree.c (replace_placeholders): Look through all handled components, - not just COMPONENT_REFs. - * typeck2.c (process_init_constructor_array): Propagate - CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to - the array initializer. +2021-01-19 Patrick Palka <ppalka@redhat.com> -2020-04-07 Jakub Jelinek <jakub@redhat.com> - - PR c++/94512 - * parser.c (cp_parser_omp_parallel): Set OMP_PARALLEL_COMBINED - if cp_parser_omp_master succeeded. - -2020-04-06 Jason Merrill <jason@redhat.com> - - PR c++/94462 - * decl.c (duplicate_decls): Fix handling of DECL_HIDDEN_FRIEND_P. - -2020-04-04 Marek Polacek <polacek@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/94155 - crash in gimplifier with paren init of aggregates. - * init.c (build_vec_init): Fill in indexes. - -2020-04-04 Jason Merrill <jason@redhat.com> - - PR c++/91377 - * mangle.c (write_expression): Skip IMPLICIT_CONV_EXPR. - -2020-04-04 Patrick Palka <ppalka@redhat.com> - - PR c++/94205 - PR c++/79937 - * constexpr.c (struct constexpr_ctx): New field 'parent'. - (cxx_eval_bare_aggregate): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY - flag from the original constructor to the reduced constructor. - (lookup_placeholder): Prefer to return the outermost matching object - by recursively calling lookup_placeholder on the 'parent' context, - but don't cross CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors. - (cxx_eval_constant_expression): Link the 'ctx' context to the 'new_ctx' - context via 'new_ctx.parent' when being expanded without an explicit - target. Don't call replace_placeholders. - (cxx_eval_outermost_constant_expr): Initialize 'ctx.parent' to NULL. - - PR c++/94219 - PR c++/94205 - * constexpr.c (get_or_insert_ctor_field): Split out (while adding - support for VECTOR_TYPEs, and optimizations for the common case) - from ... - (cxx_eval_store_expression): ... here. Rename local variable - 'changed_active_union_member_p' to 'activated_union_member_p'. Record - the sequence of indexes into 'indexes' that yields the subobject we're - assigning to. Record the integer offsets of the constructor indexes - we're assigning through into 'index_pos_hints'. After evaluating the - initializer of the store expression, recompute 'valp' using 'indexes' - and using 'index_pos_hints' as hints. - (cxx_eval_bare_aggregate): Tweak comments. Use get_or_insert_ctor_field - to recompute the constructor_elt pointer we're assigning through after - evaluating each initializer. - -2020-04-04 Jason Merrill <jason@redhat.com> - - PR c++/67825 - * constraint.cc (tsubst_valid_expression_requirement): Call - convert_to_void. - -2020-04-04 Jason Merrill <jason@redhat.com> - - PR c++/94453 - * constexpr.c (maybe_constant_value): Use break_out_target_exprs. - * expr.c (mark_use) [VIEW_CONVERT_EXPR]: Don't wrap a TARGET_EXPR in - NON_LVALUE_EXPR. - -2020-04-04 Jakub Jelinek <jakub@redhat.com> - - PR debug/94441 - * parser.c (cp_parser_omp_for_loop): Use - protected_set_expr_location_if_unset. - * cp-gimplify.c (genericize_if_stmt, genericize_cp_loop): Likewise. - - PR c++/94477 - * pt.c (tsubst_expr) <case OMP_MASTER>: Clear - omp_parallel_combined_clauses. - -2020-04-03 Jason Merrill <jason@redhat.com> - - PR c++/91966 - * pt.c (complex_pack_expansion_r): New. - (complex_alias_template_p): Use it. - -2020-03-31 Jason Merrill <jason@redhat.com> - - PR c++/94205 - * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call - replace_placeholders. - * typeck2.c (store_init_value): Fix arguments to - fold_non_dependent_expr. - -2020-03-31 Jason Merrill <jason@redhat.com> - - * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use - local variables. - -2020-03-30 Jason Merrill <jason@redhat.com> - - PR c++/90711 - * tree.c (cp_tree_equal) [CALL_EXPR]: Compare KOENIG_LOOKUP_P. - (called_fns_equal): Check DECL_CONTEXT. - -2020-03-30 Jakub Jelinek <jakub@redhat.com> - - PR c++/94385 - * semantics.c (add_stmt): Only set STMT_IS_FULL_EXPR_P on trees with - STATEMENT_CODE_P code. - -2020-03-28 Patrick Palka <ppalka@redhat.com> - - PR c++/94306 - * parser.c (cp_parser_requires_clause_opt): Diagnose and recover from - "requires {" when "requires requires {" was probably intended. - - PR c++/94252 - * constraint.cc (tsubst_compound_requirement): Always suppress errors - from type_deducible_p and expression_convertible_p, as they're not - substitution errors. - (diagnose_atomic_constraint) <case INTEGER_CST>: Remove this case so - that we diagnose INTEGER_CST expressions of non-bool type via the - default case. - * cp-gimplify.c (cp_genericize_r) <case REQUIRES_EXPR>: New case. - * parser.c (cp_parser_requires_expression): Always parse the requirement - body as if we're processing a template, by temporarily incrementing - processing_template_decl. Afterwards, if we're not actually in a - template context, perform semantic processing to diagnose any invalid - types and expressions. - * pt.c (tsubst_copy_and_build) <case REQUIRES_EXPR>: Remove dead code. - * semantics.c (finish_static_assert): Explain an assertion failure - when the condition is a REQUIRES_EXPR like we do when it is a concept - check. - - * constraint.cc (diagnose_compound_requirement): When diagnosing a - compound requirement, maybe replay the satisfaction failure, subject to - the current diagnosis depth. - - * constraint.cc (finish_constraint_binary_op): Set the location of EXPR - as well as its range, because build_x_binary_op doesn't always do so. - (current_constraint_diagnosis_depth): New. - (concepts_diagnostics_max_depth_exceeded_p): New. - (collect_operands_of_disjunction): New. - (satisfy_disjunction): When diagnosing a satisfaction failure, maybe - replay each branch of the disjunction, subject to the current diagnosis - depth. - (diagnose_valid_expression): When diagnosing a satisfaction failure, - maybe replay the substitution error, subject to the current diagnosis - recursion. - (diagnose_valid_type): Likewise. - (diagnose_nested_requiremnet): Likewise. - (diagnosing_failed_constraint::diagnosing_failed_constraint): Increment - current_constraint_diagnosis_depth when diagnosing. - (diagnosing_failed_constraint::~diagnosing_failed_constraint): Decrement - current_constraint_diagnosis_depth when diagnosing. - (diagnosing_failed_constraint::replay_errors_p): New static member - function. - (diagnose_constraints): Don't diagnose if concepts_diagnostics_max_depth - is 0. Emit a one-off note to increase -fconcepts-diagnostics-depth if - the limit was exceeded. - * cp-tree.h (diagnosing_failed_constraint::replay_errors_p): Declare. - -2020-03-27 Nathan Sidwell <nathan@acm.org> - - PR c++/84733 - * name-lookup.c (do_pushdecl): Look through cleanp levels. - -2020-03-27 Martin Sebor <msebor@redhat.com> - - PR c++/94078 - PR c++/93824 - PR c++/93810 - * cp-tree.h (most_specialized_partial_spec): Declare. - * parser.c (cp_parser_elaborated_type_specifier): Distinguish alias - from declarations. - (specialization_of): New function. - (cp_parser_check_class_key): Move code... - (class_decl_loc_t::add): ...to here. Add parameters. Avoid issuing - -Wredundant-tags on first-time declarations in other declarators. - Correct handling of template specializations. - (class_decl_loc_t::diag_mismatched_tags): Also expect to be called - when -Wredundant-tags is enabled. Use primary template or partial - specialization as the guide for uses of implicit instantiations. - * pt.c (most_specialized_partial_spec): Declare extern. - -2020-03-27 Nathan Sidwell <nathan@acm.org> - - PR c++/94257 - * name-lookup.c (push_namespace): Triage ambiguous lookups that - contain namespaces. - -2020-03-27 Jakub Jelinek <jakub@redhat.com> - - PR c++/94326 - * call.c (set_flags_from_callee): Don't update - cp_function_chain->can_throw or current_function_returns_abnormally - if cp_unevaluated_operand. - - PR c++/94339 - * cvt.c (ocp_convert): Handle COMPOUND_EXPR by recursion on the second - operand and creating a new COMPOUND_EXPR if anything changed. - -2020-03-26 Marek Polacek <polacek@redhat.com> - - PR c++/94336 - template keyword accepted before destructor names. - * parser.c (cp_parser_unqualified_id): Give an error when 'template' - is followed by a destructor name. - -2020-03-27 Patrick Palka <ppalka@redhat.com> - - * decl.c (compute_array_index_type_loc): Remove redundant - type_dependent_expression_p check that is subsumed by - value_dependent_expression_p. - * decl2.c (is_late_template_attribute): Likewise. - * pt.c (uses_template_parms): Likewise. - (dependent_template_arg_p): Likewise. - -2020-03-26 Marek Polacek <polacek@redhat.com> - - DR 1710 - PR c++/94057 - template keyword in a typename-specifier. - * parser.c (check_template_keyword_in_nested_name_spec): New. - (cp_parser_nested_name_specifier_opt): Implement DR1710, optional - 'template'. Call check_template_keyword_in_nested_name_spec. - (cp_parser_simple_type_specifier): Assume that a < - following a qualified-id in a typename-specifier begins - a template argument list. - -2020-03-26 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (coro_init_identifiers): Initialize an identifier - for the cororoutine handle 'address' method name. - (struct coro_aw_data): Add fields to cover the continuations. - (co_await_expander): Determine the kind of await_suspend in use. - If we have the case that returns a continuation handle, then save - this and make the target for 'scope exit without cleanup' be the - continuation resume label. - (expand_co_awaits): Remove. - (struct suspend_point_info): Remove fields that kept the returned - await_suspend handle type. - (transform_await_expr): Remove code tracking continuation handles. - (build_actor_fn): Add the continuation handle as an actor-function - scope var. Build the symmetric transfer continuation point. Call - the tree walk for co_await expansion directly, rather than via a - trivial shim function. - (register_await_info): Remove fields tracking continuation handles. - (get_await_suspend_return_type): Remove. - (register_awaits): Remove code tracking continuation handles. - (morph_fn_to_coro): Remove code tracking continuation handles. - -2020-03-26 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (co_await_expander): If we are expanding the - initial await expression, set a boolean flag to show that we - have now reached the initial await_resume() method call. - (expand_co_awaits): Handle the 'initial await resume called' flag. - (build_actor_fn): Insert the initial await expression into the - start of the user-authored function-body. Handle the 'initial await - resume called' flag. - (morph_fn_to_coro): Initialise the 'initial await resume called' - flag. Modify the unhandled exception catch clause to recognise - exceptions that occur before the initial await_resume() and re- - throw them. - -2020-03-26 Jakub Jelinek <jakub@redhat.com> - - PR c++/81349 - * class.c (user_provided_p): Use STRIP_TEMPLATE instead of returning - true for all TEMPLATE_DECLs. - - PR c++/94272 - * cp-gimplify.c (cp_genericize_r): Handle STATEMENT_LIST. - -2020-03-25 Patrick Palka <ppalka@redhat.com> - - PR c++/94265 - * parser.c (cp_parser_selection_statement) <case RID_IF>: Invalidate the - current condition chain when the if-statement has a non-empty - init-statement. - -2020-03-25 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/94319 - * coroutines.cc (captures_temporary): Fix a missing dereference. - -2020-03-24 Marek Polacek <polacek@redhat.com> - - PR c++/94190 - wrong no post-decrement operator error in template. - * call.c (convert_like_real): Use convert_from_reference on the result. - -2020-03-24 Jason Merrill <jason@redhat.com> - - PR c++/94186 - * constraint.cc (constraint_satisfaction_value): Repeat noisily on - error. - (tsubst_nested_requirement): Likewise. - (get_constraint_error_location): Allow missing context. - (diagnose_atomic_constraint): Diagnose non-bool constraint here. - (satisfy_atom): Not here. Only diagnose non-constant when noisy. - -2020-03-24 Jason Merrill <jason@redhat.com> - - * pt.c (any_template_parm_r): Look into the type of a non-type - template parm. - -2020-03-24 Jason Merrill <jason@redhat.com> - - * cp-tree.h (cp_expr): When constructing from an expr and a - location, call protected_set_expr_location. - -2020-03-23 Patrick Palka <ppalka@redhat.com> - - PR c++/93805 - * except.c (maybe_noexcept_warning): Add TODO. - * method.c (walk_field_subobs): Pass tf_none to expr_noexcept_p. - -2020-03-23 nathans <nathan@acm.org> - - PR c++/94044 - * tree.c (cp_tree_equal) [SIZEOF_EXPR]: Detect argument pack - operand. - -2020-03-21 Patrick Palka <ppalka@redhat.com> - - PR c++/94066 - * constexpr.c (reduced_constant_expression_p) [CONSTRUCTOR]: Properly - handle unions without an initializer. - (cxx_eval_component_reference): Emit a different diagnostic when the - constructor element corresponding to a union member is NULL. - (cxx_eval_bare_aggregate): When constructing a union, always set the - active union member before evaluating the initializer. Relax assertion - that verifies the index of the constructor element we're initializing - hasn't been changed. - (cxx_eval_store_expression): Diagnose changing the active union member - while the union is in the process of being initialized. After setting - an active union member, clear CONSTRUCTOR_NO_CLEARING on the underlying - CONSTRUCTOR. - (cxx_eval_constant_expression) [PLACEHOLDER_EXPR]: Don't re-reduce a - CONSTRUCTOR returned by lookup_placeholder. - -2020-03-20 Patrick Palka <ppalka@redhat.com> - - * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. Move - the "[with ]" bits to here from ... - (pp_cxx_atomic_constraint): ... here. - * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. - * error.c (rebuild_concept_check): Delete. - (print_concept_check_info): Print the dependent form of the constraint and the - preferably substituted parameter mapping alongside it. - -2020-03-19 Jason Merrill <jason@redhat.com> - - PR c++/94175 - * cp-gimplify.c (simple_empty_class_p): Look through - SIMPLE_TARGET_EXPR_P. - (cp_gimplify_expr) [MODIFY_EXPR]: Likewise. - [RETURN_EXPR]: Avoid producing 'return *retval;'. - * call.c (build_call_a): Strip TARGET_EXPR from empty class arg. - * cp-tree.h (SIMPLE_TARGET_EXPR_P): Check that TARGET_EXPR_INITIAL - is non-null. - -2020-03-19 Jakub Jelinek <jakub@redhat.com> - - PR c++/93931 - * parser.c (cp_parser_omp_var_list_no_open): Call process_outer_var_ref - on outer_automatic_var_p decls. - * cp-gimplify.c (cxx_omp_disregard_value_expr): Return true also for - capture proxy decls. - -2020-03-18 Nathan Sidwell <nathan@acm.org> - - PR c++/94147 - mangling of lambdas assigned to globals - * parser.c (cp_parser_init_declarator): Namespace-scope variables - provide a lambda scope. - * tree.c (no_linkage_check): Lambdas with a variable for extra - scope have a linkage from the variable. - -2020-03-18 Jakub Jelinek <jakub@redhat.com> - - * constraint.cc (resolve_function_concept_check, subsumes_constraints, - strictly_subsumes): Fix up duplicated word issue in a comment. - * coroutines.cc (build_init_or_final_await, captures_temporary): - Likewise. - * logic.cc (dnf_size_r, cnf_size_r): Likewise. - * pt.c (append_type_to_template_for_access_check): Likewise. - - PR c++/91759 - * decl.c (grokfndecl): Restore old diagnostics about deduction - guide declared in different scope if in_namespace is NULL_TREE. - -2020-03-17 Jakub Jelinek <jakub@redhat.com> - - PR c++/90995 - * parser.c (cp_parser_enum_specifier): Use temp_override for - parser->colon_corrects_to_scope_p, replace goto out with return. - If scoped enum or enum with underlying type is not followed by - { or ;, call cp_parser_commit_to_tentative_parse before calling - cp_parser_error and make sure to return error_mark_node instead of - NULL_TREE. Formatting fixes. - -2020-03-17 Ville Voutilainen <ville.voutilainen@gmail.com> - - PR c++/94197 - * method.c (assignable_expr): Use cp_unevaluated. - (is_xible_helper): Push a non-deferred access check for - the stub objects created by assignable_expr and constructible_expr. - -2020-03-17 Jakub Jelinek <jakub@redhat.com> - - * pt.c (tsubst): Fix up duplicated word issue in a diagnostic message. - (lookup_template_class_1, tsubst_expr): Fix up duplicated word issue - in a comment. - * parser.c (cp_parser_statement, cp_parser_linkage_specification, - cp_parser_placeholder_type_specifier, - cp_parser_constraint_requires_parens): Likewise. - * name-lookup.c (suggest_alternative_in_explicit_scope): Likewise. - -2020-03-15 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (co_await_expander): Fix indentation. - -2020-03-14 Jason Merrill <jason@redhat.com> - - PR c++/92068 - * pt.c (process_partial_specialization): Error rather than crash on - extra pack expansion. - -2020-03-14 Jason Merrill <jason@redhat.com> - - PR c++/92909 - * pt.c (find_parameter_packs_r): [DECL_EXPR]: Walk - DECL_ORIGINAL_TYPE of a typedef. - -2020-03-14 Jason Merrill <jason@redhat.com> - - PR c++/93248 - * pt.c (build_deduction_guide): Clear cp_unevaluated_operand for - substituting DECL_ARGUMENTS. - -2020-03-14 Jakub Jelinek <jakub@redhat.com> - - * logic.cc (formula::formula): Change "a an" to "an" in a comment. - * parser.c (cp_debug_parser): Change "a an" to "an" in a string - literal. - -2020-03-13 Patrick Palka <ppalka@redhat.com> - - PR c++/67960 - * call.c (build_over_call): Use a warning_sentinel to disable - warn_deprecated_decl before calling build_addr_func. - -2020-03-12 Jakub Jelinek <jakub@redhat.com> - - PR c++/94124 - * decl.c (reshape_init_array_1): Don't unshare constructor if there - aren't any trailing zero elts, otherwise only unshare the first - nelts. - -2020-03-11 Jason Merrill <jason@redhat.com> - - PR c++/93907 - * constraint.cc (tsubst_parameter_mapping): Canonicalize type - argument. - -2020-03-11 Marek Polacek <polacek@redhat.com> - Jason Merrill <jason@redhat.com> - - PR c++/94074 - wrong modifying const object error for COMPONENT_REF. - * constexpr.c (cref_has_const_field): New function. - (modifying_const_object_p): Consider a COMPONENT_REF - const only if any of its fields are const. - (cxx_eval_store_expression): Mark a CONSTRUCTOR of a const type - as readonly after its initialization has been done. - -2020-03-10 Marek Polacek <polacek@redhat.com> - - PR c++/94124 - wrong conversion error with non-viable overload. - * decl.c (reshape_init_array_1): Unshare a constructor if we - stripped trailing zero-initializers. - -2020-03-10 Jason Merrill <jason@redhat.com> - - PR c++/93901 - * pt.c (maybe_instantiate_noexcept): Always update clones. - -2020-03-10 Jason Merrill <jason@redhat.com> - - PR c++/93596 - * pt.c (maybe_aggr_guide): Check BRACE_ENCLOSED_INITIALIZER_P. - -2020-03-10 Jason Merrill <jason@redhat.com> - - PR c++/93922 - PR c++/94041 - PR c++/52320 - PR c++/66139 - * cp-gimplify.c (cp_gimplify_init_expr): Partially revert patch for - 66139: Don't split_nonconstant_init. Remove pre_p parameter. - -2020-03-09 Marek Polacek <polacek@redhat.com> - - PR c++/92031 - bogus taking address of rvalue error. - PR c++/91465 - ICE with template codes in check_narrowing. - PR c++/93870 - wrong error when converting template non-type arg. - PR c++/94068 - ICE with template codes in check_narrowing. - * call.c (convert_like_real): Return IMPLICIT_CONV_EXPR - in a template when not ck_identity and we're dealing with a class. - (convert_like_real) <case ck_ref_bind>: Return IMPLICIT_CONV_EXPR - in a template if we need a temporary. - * decl.c (compute_array_index_type_loc): Remove - instantiate_non_dependent_expr_sfinae call. Call - fold_non_dependent_expr instead of maybe_constant_value. - (build_explicit_specifier): Don't instantiate or create a sentinel - before converting the expression. - * except.c (build_noexcept_spec): Likewise. - * pt.c (convert_nontype_argument): Don't build IMPLICIT_CONV_EXPR. - Set IMPLICIT_CONV_EXPR_NONTYPE_ARG if that's what - build_converted_constant_expr returned. - * typeck2.c (check_narrowing): Call fold_non_dependent_expr instead - of maybe_constant_value. - -2020-03-09 Jakub Jelinek <jakub@redhat.com> - - PR c++/94067 - Revert - 2019-10-11 Paolo Carlini <paolo.carlini@oracle.com> - - * constexpr.c (cxx_eval_constant_expression): Do not handle - RROTATE_EXPR and LROTATE_EXPR. - -2020-03-09 Marek Polacek <polacek@redhat.com> - - PR c++/94050 - ABI issue with alignas on armv7hl. - * class.c (layout_class_type): Don't replace a class's - CLASSTYPE_AS_BASE if their TYPE_USER_ALIGN don't match. - -2020-03-09 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (build_actor_fn): Factor out code inserting the - default return_void call to... - (morph_fn_to_coro): ...here, also hoist local var declarations. - -2020-03-08 Patrick Palka <ppalka@redhat.com> - - PR c++/93729 - * call.c (convert_like_real): Check complain before emitting an error - about binding a bit-field to a reference. - - * cxx-pretty-print.c (cxx_pretty_printer::simple_type_specifier) - [TYPENAME_TYPE]: Print the TYPENAME_TYPE_FULLNAME instead of the - TYPE_NAME. - -2020-03-06 Nathan Sidwell <nathan@acm.org> - - PR c++/94027 - * mangle.c (find_substitution): Don't call same_type_p on template - args that cannot match. - -2020-03-04 Martin Sebor <msebor@redhat.com> - - PR c++/90938 - * tree.c (type_initializer_zero_p): Fail for structs initialized - with non-structs. - -2020-03-04 Jason Merrill <jason@redhat.com> - - PR c++/90432 - * init.c (perform_member_init): Don't do aggregate initialization of - empty field. - * constexpr.c (cx_check_missing_mem_inits): Don't enforce - initialization of empty field. - -2020-03-04 Martin Liska <mliska@suse.cz> - - * method.c: Wrap array in ctor with braces in order - to silent clang warnings. - -2020-03-03 Jason Merrill <jason@redhat.com> - Marek Polacek <polacek@redhat.com> - - PR c++/90505 - mismatch in template argument deduction. - * pt.c (tsubst): Don't reduce the template level of template - parameters when tf_partial. - -2020-03-03 Jakub Jelinek <jakub@redhat.com> - - PR c++/93998 - * constexpr.c (cxx_eval_constant_expression) - <case TARGET_EXPR, case SAVE_EXPR>: Don't record anything if - *non_constant_p is true. - -2020-03-03 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (captures_temporary): Strip component_ref - to its base object. - -2020-03-03 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (finish_co_await_expr): Build co_await_expr - with unknown_type_node. - (finish_co_yield_expr): Ditto. - *pt.c (type_dependent_expression_p): Set co_await/yield_expr - with unknown type as dependent. - -2020-03-02 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (struct local_var_info): Adjust to remove the - reference to the captured var, and just to note that this is a - lambda capture proxy. - (transform_local_var_uses): Handle lambda captures specially. - (struct param_frame_data): Add a visited set. - (register_param_uses): Also check for param uses in lambda - capture proxies. - (struct local_vars_frame_data): Remove captures list. - (register_local_var_uses): Handle lambda capture proxies by - noting and bypassing them. - (morph_fn_to_coro): Update to remove lifetime extension of - lambda capture-by-copy vars. - -2020-03-02 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (build_co_await): Do not build frame - awaitable proxy vars when the co_await expression is - a function parameter or local var. - (co_await_expander): Do not initialise a frame var with - itself. - (transform_await_expr): Only substitute the awaitable - frame var if it's needed. - (register_awaits): Do not make frame copies for param - or local vars that are awaitables. - -2020-02-28 Jason Merrill <jason@redhat.com> - - Implement P2092R0, Disambiguating Nested-Requirements - * parser.c (cp_parser_requirement_parameter_list): Pass - CP_PARSER_FLAGS_TYPENAME_OPTIONAL. - - * call.c (build_user_type_conversion_1): Don't look at the second - conversion of a non-viable candidate. - -2020-02-28 Jakub Jelinek <jakub@redhat.com> - - P1937R2 - Fixing inconsistencies between const{expr,eval} functions - * typeck.c (cp_build_addr_expr_1): Allow taking address of immediate - functions in unevaluated contexts. - -2020-02-27 Nathan Sidwell <nathan@acm.org> - - PR c++/93933 - * pt.c (template_args_equal): Pass ARGUMENT_PACKS through to - cp_tree_equal. - * tree.c (cp_tree_equal): Compare ARGUMENT_PACKS here, - * typeck.c (comptypes): Assert we don't get any argument packs. - - * class.c (adjust_clone_args): Correct arg-checking assert. - * typeck.c (comptypes): Assert not nulls. - -2020-02-26 Marek Polacek <polacek@redhat.com> - - PR c++/93789 - ICE with invalid array bounds. - * decl.c (compute_array_index_type_loc): Don't use the folded - size when folding cleared TREE_CONSTANT. - -2020-02-26 Iain Sandoe <iain@sandoe.co.uk> - - * class.c (classtype_has_non_deleted_copy_ctor): New. - * coroutines.cc (struct param_info): Keep track of params - that are references, and cache the original type and whether - the DTOR is trivial. - (build_actor_fn): Handle param copies always, and adjust the - handling for references. - (register_param_uses): Only handle uses here. - (classtype_has_non_deleted_copy_ctor): New. - (morph_fn_to_coro): Adjust param copy handling to match n4849 - by reordering ahead of the promise CTOR and always making a - frame copy, even if the param is unused in the coroutine body. - * cp-tree.h (classtype_has_non_deleted_copy_ctor): New. - -2020-02-26 Patrick Palka <ppalka@redhat.com> - - * constraint.cc (finish_constraint_binary_op): Set expr's location range - to the range of its operands. - (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint. - (diagnose_trait_expr): Take the instantiated parameter mapping MAP - instead of the corresponding template arguments ARGS and adjust body - accordingly. - (diagnose_requires_expr): Likewise. - (diagnose_atomic_constraint): Likewise. When printing an atomic - constraint expression, print the instantiated parameter mapping - alongside it. - * cxx-pretty-print.cc (cxx_pretty_printer::expression) - [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK. - (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK. - -2020-02-26 Marek Polacek <polacek@redhat.com> - - PR c++/93676 - value-init crash in template. - * init.c (build_new_1): Don't call build_vec_init in a template. - -2020-02-26 Marek Polacek <polacek@redhat.com> - - PR c++/93862 - ICE with static_cast when converting from int[]. - * call.c (reference_compatible_p): No longer static. - * cp-tree.h (reference_compatible_p): Declare. - * typeck.c (build_static_cast_1): Use reference_compatible_p instead - of reference_related_p. - -2020-02-26 Marek Polacek <polacek@redhat.com> - - PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. - * constexpr.c (reduced_constant_expression_p): Don't crash on a null - field. - -2020-02-24 Martin Sebor <msebor@redhat.com> - - PR c++/93804 - * parser.c (cp_parser_check_class_key): Avoid issuing -Wredundant-tags - in shared C/C++ code in headers. - Remove a duplicate hunk of code. - -2020-02-24 Marek Polacek <polacek@redhat.com> - - PR c++/93869 - ICE with -Wmismatched-tags. - * parser.c (cp_parser_check_class_key): Check class_key earlier. - -2020-02-24 Marek Polacek <polacek@redhat.com> - - PR c++/93712 - ICE with ill-formed array list-initialization. - * call.c (next_conversion): Return NULL for ck_aggr. - (build_aggr_conv): Set u.expr instead of u.next. - (build_array_conv): Likewise. - (build_complex_conv): Likewise. - (conv_get_original_expr): Handle ck_aggr. - -2020-02-24 Jakub Jelinek <jakub@redhat.com> - - P1937R2 - Fixing inconsistencies between const{expr,eval} functions - * call.c (build_over_call): Don't evaluate immediate functions in - unevaluated operands. - -2020-02-24 Jason Merrill <jason@redhat.com> - - P0780R2: Resolve lambda init-capture pack grammar. - * parser.c (cp_parser_lambda_introducer): Expect &...x=y rather than - ...&x=y. - -2020-02-22 Marek Polacek <polacek@redhat.com> - - PR c++/93882 - * decl.c (grokdeclarator): Use %qs in a diagnostic message. - -2020-02-21 Martin Sebor <msebor@redhat.com> - - PR gcov-profile/93753 - * class.c (check_flexarrays): Tighten up a test for potential members - of anonymous structs or unions. - -2020-02-20 Martin Sebor <msebor@redhat.com> - - PR c++/93801 - * parser.c (cp_parser_check_class_key): Only handle true C++ class-keys. - -2020-02-20 Martin Liska <mliska@suse.cz> - - PR translation/93841 - * config/or1k/or1k.opt: Remove superfluous word. - * doc/invoke.texi: Likewise. - -2020-02-20 Martin Liska <mliska@suse.cz> - - PR translation/93838 - * parser.c (cp_parser_decl_specifier_seq): Remove trailing space. - -2020-02-19 Marek Polacek <polacek@redhat.com> - - PR c++/93169 - wrong-code with a non-constexpr constructor. - * constexpr.c (cxx_eval_call_expression): Only set TREE_READONLY - on constant CONSTRUCTORs. - -2020-02-15 Marek Polacek <polacek@redhat.com> - - PR c++/93710 - poor diagnostic for array initializer. - * call.c (build_user_type_conversion_1): Use cp_expr_loc_or_input_loc - for an error call. - -2020-02-15 Jason Merrill <jason@redhat.com> - - PR c++/92556 - * pt.c (any_template_parm_r): Look into lambda body. - - PR c++/92583 - * pt.c (any_template_parm_r): Remove CONSTRUCTOR handling. - -2020-02-14 Jakub Jelinek <jakub@redhat.com> - - PR c++/61414 - * class.c (enum_min_precision): Change prec type from int to int &. - - PR libstdc++/92906 - * cp-tree.h (enum cp_tree_index): Add CPTI_FALLBACK_DFLOAT32_TYPE, - CPTI_FALLBACK_DFLOAT64_TYPE and CPTI_FALLBACK_DFLOAT128_TYPE. - (fallback_dfloat32_type, fallback_dfloat64_type, - fallback_dfloat128_type): Define. - * mangle.c (write_builtin_type): Handle fallback_dfloat*_type like - dfloat*_type_node. - * rtti.c (emit_support_tinfos): Emit DFP typeinfos even when dfp - is disabled for compatibility. - -2020-02-13 Jason Merrill <jason@redhat.com> - - PR c++/93713 - * name-lookup.c (matching_fn_p): A function does not match a - template. - - PR c++/93643 - PR c++/91476 - * tree.c (decl_linkage): Always lk_none for locals. - -2020-02-12 Jason Merrill <jason@redhat.com> - - PR c++/92583 - PR c++/92654 - * tree.c (cp_walk_subtrees): Walk CONSTRUCTOR types here. - * pt.c (find_parameter_packs_r): Not here. - -2020-02-12 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (build_actor_fn): Implement deallocation function - selection per n4849, dcl.fct.def.coroutine bullet 12. - (morph_fn_to_coro): Implement allocation function selection per - n4849, dcl.fct.def.coroutine bullets 9 and 10. - -2020-02-12 Marek Polacek <polacek@redhat.com> - - PR c++/93684 - ICE-on-invalid with broken attribute. - * parser.c (cp_parser_std_attribute): Peek a token first before - consuming it. - -2020-02-11 Jason Merrill <jason@redhat.com> - - PR c++/93675 - * class.c (add_implicitly_declared_members): Use do_friend. - * method.c (implicitly_declare_fn): Fix friend handling. - (decl_remember_implicit_trigger_p): New. - (synthesize_method): Use it. - * decl2.c (mark_used): Use it. - -2020-02-11 Jason Merrill <jason@redhat.com> - - PR c++/93650 - PR c++/90691 - * constexpr.c (maybe_constant_value): Correct earlier change. - (cxx_eval_binary_expression) [SPACESHIP_EXPR]: Pass lval through. - * method.c (genericize_spaceship): Wrap result in TARGET_EXPR. - -2020-02-12 Patrick Palka <ppalka@redhat.com> - - PR c++/69448 - PR c++/80471 - * type-utils.h (find_type_usage): Refactor to take a tree * and to - return a tree *, and update documentation accordingly. - * pt.c (make_auto_1): Set AUTO_IS_DECLTYPE when building a - decltype(auto) node. - (make_constrained_decltype_auto): No need to explicitly set - AUTO_IS_DECLTYPE anymore. - (splice_late_return_type): Use find_type_usage to find and - replace a possibly nested auto node instead of using is_auto. - Check test for is_auto into an assert when deciding whether - to late_return_type. - (type_uses_auto): Adjust the call to find_type_usage. - * parser.c (cp_parser_decltype): No need to explicitly set - AUTO_IS_DECLTYPE anymore. - - * error.c (dump_decl) [CONCEPT_DECL]: Use dump_simple_decl. - (dump_simple_decl): Handle standard concept definitions as well as - variable concept definitions. - -2020-02-10 Jakub Jelinek <jakub@redhat.com> - - PR other/93641 - * error.c (dump_decl_name): Fix up last argument to strncmp. - -2020-02-10 Jason Merrill <jason@redhat.com> - - PR c++/93618 - * tree.c (array_of_unknown_bound_p): New. - * init.c (perform_member_init): Do nothing for flexible arrays. - -2020-02-09 Jakub Jelinek <jakub@redhat.com> - - PR c++/93633 - * constexpr.c (cxx_eval_constant_expression): If obj is heap var with - ARRAY_TYPE, use the element type. Punt if objtype after that is not - a class type. - -2020-02-08 Jason Merrill <jason@redhat.com> - - PR c++/90691 - * expr.c (fold_for_warn): Call maybe_constant_value. - * constexpr.c (struct constexpr_ctx): Add uid_sensitive bit-field. - (maybe_constant_value): Add uid_sensitive parm. - (get_fundef_copy): Don't copy if it's true. - (cxx_eval_call_expression): Don't instantiate if it's true. - (cxx_eval_outermost_constant_expr): Likewise. - - PR c++/92852 - * constexpr.c (maybe_constant_value): Don't unshare if the cached - value is the same as the argument. - - * typeck.c (maybe_warn_about_returning_address_of_local): Add - location parameter. - - * typeck2.c (process_init_constructor): Also clear TREE_SIDE_EFFECTS - if appropriate. - -2020-02-08 Jakub Jelinek <jakub@redhat.com> - - PR c++/93549 - * constexpr.c (find_array_ctor_elt): If last element has no index, - for flag_checking verify all elts have no index. If i is within the - elts, return it directly, if it is right after the last elt, append - if NULL index, otherwise force indexes on all elts. - (cxx_eval_store_expression): Allow cep->index to be NULL. - -2020-02-07 Marek Polacek <polacek@redhat.com> - - PR c++/92947 - Paren init of aggregates in unevaluated context. - * call.c (build_new_method_call_1): Don't check - cp_unevaluated_operand. Check the return value of digest_init. - -2020-02-06 Jason Merrill <jason@redhat.com> - - PR c++/92654 - * tree.c (cp_walk_subtrees): Walk into type template arguments. - * cp-tree.h (TYPE_TEMPLATE_INFO_MAYBE_ALIAS): Use typedef_variant_p - instead of TYPE_ALIAS_P. - * pt.c (push_template_decl_real): Likewise. - (find_parameter_packs_r): Likewise. Remove dead code. - * error.c (find_typenames_r): Remove dead code. - -2020-02-06 Jason Merrill <jason@redhat.com> - - PR c++/92517 - * parser.c (cp_parser_constraint_primary_expression): Do the main - parse non-tentatively. - -2020-02-06 Marek Polacek <polacek@redhat.com> - - PR c++/93597 - ICE with lambda in operator function. - * name-lookup.c (maybe_save_operator_binding): Check is_overloaded_fn. - -2020-02-05 Jason Merrill <jason@redhat.com> - - PR c++/93140 - * pt.c (tsubst_decl) [PARM_DECL]: Check cp_unevaluated_operand in - handling of TREE_CHAIN for empty pack. - -2020-02-05 Jakub Jelinek <jakub@redhat.com> - - PR c++/93557 - * semantics.c (cp_build_vec_convert): Call decay_conversion on arg - prior to passing it to c_build_vec_convert. - -2020-02-05 Marek Polacek <polacek@redhat.com> - - PR c++/93559 - ICE with CONSTRUCTOR flags verification. - * decl.c (reshape_init_array_1): Don't reuse a CONSTRUCTOR with - TREE_SIDE_EFFECTS. - -2020-02-05 Jason Merrill <jason@redhat.com> - - PR c++/92593 - * decl.c (grokdeclarator): Reject field of current class type even - in a template. - -2020-02-05 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (maybe_promote_captured_temps): Increase the index - number for temporary variables' name. - -2020-02-05 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (build_co_await): Call convert_from_reference - to wrap co_await_expr with indirect_ref which avoid - reference/non-reference type confusion. - - (co_await_expander): Sink to call_expr if await_resume - is wrapped by indirect_ref. - -2020-02-04 Jason Merrill <jason@redhat.com> - - PR c++/93551 - * constraint.cc (satisfy_declaration_constraints): Check return - value of push_tinst_level. - - PR c++/90951 - * constexpr.c (cxx_eval_array_reference): {}-initialize missing - elements instead of value-initializing them. - - PR c++/86917 - * init.c (perform_member_init): Simplify. - * constexpr.c (cx_check_missing_mem_inits): Allow uninitialized - flexarray. - (cxx_eval_vec_init_1): Handle CONSTRUCTOR. - -2020-02-04 Iain Sandoe <iain@sandoe.co.uk> - - * coroutines.cc (find_promise_type): Delete unused forward - declaration. - (struct coroutine_info): Add a bool for no promise type error. - (coro_promise_type_found_p): Only emit the error for a missing - promise once in each affected coroutine. - -2020-02-03 Jason Merrill <jason@redhat.com> - - PR c++/66477 - * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't - defer loading the value of a reference. - -2020-02-03 Jason Merrill <jason@redhat.com> - - PR c++/91953 - * constexpr.c (potential_constant_expression_1) [PARM_DECL]: Allow - empty class type. - [COMPONENT_REF]: A member function reference doesn't use the object - as an rvalue. - -2020-02-03 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/93458 - * coroutines.cc (struct coroutine_info): Add a bool flag to note - that we emitted an error for a bad function return type. - (get_coroutine_info): Tolerate an unset info table in case of - missing traits. - (find_coro_traits_template_decl): In case of error or if we didn't - find a type template, note we emitted the error and suppress - duplicates. - (find_coro_handle_template_decl): Likewise. - (instantiate_coro_traits): Only check for error_mark_node in the - return from lookup_qualified_name. - (coro_promise_type_found_p): Reorder initialization so that we check - for the traits and their usability before allocation of the info - table. Check for a suitable return type and emit a diagnostic for - here instead of relying on the lookup machinery. This allows the - error to have a better location, and means we can suppress multiple - copies. - (coro_function_valid_p): Re-check for a valid promise (and thus the - traits) before proceeding. Tolerate missing info as a fatal error. - -2020-02-03 Jason Merrill <jason@redhat.com> - - PR c++/88256 - * cp-gimplify.c (predeclare_vla): New. - (cp_genericize_r) [NOP_EXPR]: Call it. - -2020-02-03 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (transform_await_wrapper): Set actor funcion as - new context of label_decl. - (build_actor_fn): Fill new field of await_xform_data. - -2020-02-02 Marek Polacek <polacek@redhat.com> - - PR c++/93530 - ICE on invalid alignas in a template. - * decl.c (grokdeclarator): Call cplus_decl_attributes instead of - decl_attributes. - -2020-01-31 Jason Merrill <jason@redhat.com> - - PR c++/86216 - * semantics.c (process_outer_var_ref): Capture VLAs even in - unevaluated context. - - PR c++/14179 - * decl.c (reshape_init_array_1): Reuse a single CONSTRUCTOR with - non-aggregate elements. - (reshape_init_array): Add first_initializer_p parm. - (reshape_init_r): Change first_initializer_p from bool to tree. - (reshape_init): Pass init to it. - - PR c++/14179 - * parser.c (cp_parser_initializer_list): Suppress location wrappers - after 256 elements. - -2020-01-29 Jason Merrill <jason@redhat.com> - - PR c++/82521 - * pt.c (tsubst_copy_and_build) [EQ_EXPR]: Only suppress warnings if - the expression was dependent before substitution. - -2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (act_des_fn): New. - (morph_fn_to_coro): Call act_des_fn to build actor/destroy decls. - Access promise via actor function's frame pointer argument. - (build_actor_fn, build_destroy_fn): Use frame pointer argument. - -2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (co_await_expander): Handle type conversion case. - -2020-01-29 Jason Merrill <jason@redhat.com> - - PR c++/90333 - PR c++/89640 - PR c++/60503 - * parser.c (cp_parser_type_specifier_seq): Don't parse attributes in - a trailing return type. - (cp_parser_lambda_declarator_opt): Parse C++11 attributes before - parens. - -2020-01-29 Marek Polacek <polacek@redhat.com> - - PR c++/91754 - Fix template arguments comparison with class NTTP. - * pt.c (class_nttp_const_wrapper_p): New. - (template_args_equal): See through class_nttp_const_wrapper_p - arguments. - -2020-01-29 Marek Polacek <polacek@redhat.com> - - PR c++/92948 - Fix class NTTP with template arguments. - * pt.c (convert_nontype_argument): Use IMPLICIT_CONV_EXPR when - converting a value-dependent expression to a class type. - (tsubst_copy) <case VIEW_CONVERT_EXPR>: Allow IMPLICIT_CONV_EXPR - as the result of the tsubst_copy call. - -2020-01-29 Jakub Jelinek <jakub@redhat.com> - - PR c++/91118 - * cp-gimplify.c (cxx_omp_predetermined_sharing): Return - OMP_CLAUSE_DEFAULT_SHARED for typeinfo decls. - -2020-01-28 Jason Merrill <jason@redhat.com> - - PR c++/93442 - * parser.c (cp_parser_lambda_expression): Clear in_discarded_stmt. - - PR c++/93477 - PR c++/91476 - * decl2.c (copy_linkage): Do copy DECL_ONE_ONLY and DECL_WEAK. - - PR c++/90546 - * call.c (build_user_type_conversion_1): Allow a template conversion - returning an rvalue reference to bind directly to an lvalue. - - PR c++/90731 - * decl.c (grokdeclarator): Propagate eh spec from typedef. - -2020-01-28 Martin Liska <mliska@suse.cz> - - PR c++/92440 - * pt.c (redeclare_class_template): Group couple of - errors and inform messages with auto_diagnostic_group. - -2020-01-28 Martin Liska <mliska@suse.cz> - - PR c++/92440 - * pt.c (redeclare_class_template): Use inform - for the second location. - -2020-01-27 Jason Merrill <jason@redhat.com> - - PR c++/90966 - * pt.c (tsubst_copy) [STRING_CST]: Don't use fold_convert. - -2020-01-27 Iain Sandoe <iain@sandoe.co.uk> - - PR c++/93443 - * coroutines.cc (morph_fn_to_coro): Check the ramp return - value when it is constructed from the 'get return object'. - -2020-01-27 Nathan Sidwell <nathan@acm.org> - - PR c++/91826 - * name-lookup.c (is_ancestor): Allow CHILD to be a namespace alias. - -2020-01-26 Jason Merrill <jason@redhat.com> - - PR c++/90992 - * except.c (maybe_noexcept_warning): Check DECL_IN_SYSTEM_HEADER and - temporarily enable -Wsystem-headers. Change second warning to - conditional inform. - - PR c++/90997 - * semantics.c (finish_call_expr): Don't call - instantiate_non_dependent_expr before warn_for_memset. - -2020-01-25 Marek Polacek <polacek@redhat.com> - - PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context. - * constexpr.c (cxx_eval_dynamic_cast_fn): Add a reference - dynamic_cast diagnostic. - -2020-01-24 Jason Merrill <jason@redhat.com> - - PR c++/93400 - ICE with constrained friend. - * constraint.cc (maybe_substitute_reqs_for): New. - * decl.c (function_requirements_equivalent_p): Call it. - * pt.c (tsubst_friend_function): Only substitute - TEMPLATE_PARMS_CONSTRAINTS. - (tsubst_template_parms): Copy constraints. - -2020-01-24 Jason Merrill <jason@redhat.com> - - PR c++/93279 - ICE with lambda in member operator. - * name-lookup.c (maybe_save_operator_binding): Don't remember - class-scope bindings. - -2020-01-24 Jason Merrill <jason@redhat.com> - - PR c++/93377 - ICE with member alias in constraint. - * pt.c (any_template_parm_r): Look at template arguments for all - aliases, not only alias templates. - -2020-01-24 Marek Polacek <polacek@redhat.com> - - PR c++/93299 - ICE in tsubst_copy with parenthesized expression. - * pt.c (tsubst_copy): Handle a REF_PARENTHESIZED_P VIEW_CONVERT_EXPR. - -2020-01-24 Jason Merrill <jason@redhat.com> - - PR c++/92852 - ICE with generic lambda and reference var. - * constexpr.c (maybe_constant_value): Likewise. - -2020-01-23 Paolo Carlini <paolo.carlini@oracle.com> - - PR c++/92804 - * parser.c (cp_parser_nested_name_specifier_opt): Properly - diagnose concept-ids. - -2020-01-23 Jason Merrill <jason@redhat.com> - - PR c++/93331 - ICE with __builtin_strchr. - * constexpr.c (cxx_eval_builtin_function_call): Use the original - argument if we didn't manage to extract a STRING_CST. - - PR c++/93345 - ICE with defaulted dtor and template. - PR c++/33799 - * decl.c (cxx_maybe_build_cleanup): Don't try to set - throwing_cleanup in a template. - -2020-01-22 Marek Polacek <polacek@redhat.com> - - PR c++/92907 - noexcept does not consider "const" in member functions. - * g++.dg/cpp0x/noexcept56.C: New test. - -2020-01-22 Marek Polacek <polacek@redhat.com> - - PR c++/93324 - ICE with -Wall on constexpr if. - * semantics.c (is_std_constant_evaluated_p): Check fndecl. - -2020-01-22 Patrick Palka <ppalka@redhat.com> - - * constraint.cc (get_mapped_args): Avoid using auto_vec - as a vector element. Release the vectors inside the lists - vector. - * parser.c (cp_literal_operator_id): Free the buffer. - -2020-01-22 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (finish_co_await_expr): Add error check on return - value of build_co_await. - (finish_co_yield_expr,): Ditto. - -2020-01-22 Jun Ma <JunMa@linux.alibaba.com> - - * coroutines.cc (lookup_awaitable_member): Lookup an awaitable member. - (lookup_promise_method): Emit diagnostic when get NULL_TREE back only. - (build_co_await): Use lookup_awaitable_member instead of lookup_member. - -2020-01-21 Jason Merrill <jason@redhat.com> - - PR c++/60855 - ICE with sizeof VLA capture. - * lambda.c (is_lambda_ignored_entity): Don't look past VLA capture. - - PR c++/90732 - ICE with VLA capture and generic lambda. - * pt.c (tsubst_lambda_expr): Repeat add_capture for VLAs. - -2020-01-21 Iain Sandoe <iain@sandoe.co.uk> - Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (coro_promise_type_found_p): Check for NULL return - from complete_type_or_else. - (register_param_uses): Likewise. - (build_co_await): Do not try to use complete_type_or_else for void - types, otherwise for incomplete types, check for NULL return from - complete_type_or_else. - -2020-01-21 Jason Merrill <jason@redhat.com> - - PR c++/91476 - anon-namespace reference temp clash between TUs. - * decl2.c (copy_linkage): Factor out of get_guard. - * call.c (make_temporary_var_for_ref_to_temp): Use it. - * decl.c (cp_finish_decomp): Use it. - (cp_finish_decl): determine_visibility sooner. - -2020-01-21 Bin Cheng <bin.cheng@linux.alibaba.com> - - * coroutines.cc (finish_co_await_expr): Set return value flag. - (finish_co_yield_expr, morph_fn_to_coro): Ditto. - -2020-01-19 Jason Merrill <jason@redhat.com> - - PR c++/33799 - destroy return value, take 2. - * cp-tree.h (current_retval_sentinel): New macro. - (struct language_function): Add throwing_cleanup bitfield. - * decl.c (cxx_maybe_build_cleanup): Set it. - * except.c (maybe_set_retval_sentinel) - (maybe_splice_retval_cleanup): New functions. - * parser.c (cp_parser_compound_statement): Call - maybe_splice_retval_cleanup. - * typeck.c (check_return_expr): Call maybe_set_retval_sentinel. - - * parser.c (cp_parser_lambda_body): Use cp_parser_function_body. - -2020-01-18 Jakub Jelinek <jakub@redhat.com> - - * coroutines.cc (get_fn_local_identifier): Fix NO_DOT_IN_LABEL - but non-NO_DOLLAR_IN_LABEL case build. + PR c++/41437 + PR c++/58993 + * search.c (friend_accessible_p): If scope is a hidden friend + defined inside a dependent class, consider access from the + class. + * parser.c (cp_parser_late_parsing_for_member): Don't push a + dk_no_check access state. -2020-01-18 Iain Sandoe <iain@sandoe.co.uk> +2021-01-19 Marek Polacek <polacek@redhat.com> - * Make-lang.in: Add coroutines.o. - * cp-tree.h (lang_decl-fn): coroutine_p, new bit. - (DECL_COROUTINE_P): New. - * lex.c (init_reswords): Enable keywords when the coroutine flag - is set, - * operators.def (co_await): New operator. - * call.c (add_builtin_candidates): Handle CO_AWAIT_EXPR. - (op_error): Likewise. - (build_new_op_1): Likewise. - (build_new_function_call): Validate coroutine builtin arguments. - * constexpr.c (potential_constant_expression_1): Handle - CO_AWAIT_EXPR, CO_YIELD_EXPR, CO_RETURN_EXPR. - * coroutines.cc: New file. - * cp-objcp-common.c (cp_common_init_ts): Add CO_AWAIT_EXPR, - CO_YIELD_EXPR, CO_RETRN_EXPR as TS expressions. - * cp-tree.def (CO_AWAIT_EXPR, CO_YIELD_EXPR, (CO_RETURN_EXPR): New. - * cp-tree.h (coro_validate_builtin_call): New. - * decl.c (emit_coro_helper): New. - (finish_function): Handle the case when a function is found to - be a coroutine, perform the outlining and emit the outlined - functions. Set a bit to signal that this is a coroutine component. - * parser.c (enum required_token): New enumeration RT_CO_YIELD. - (cp_parser_unary_expression): Handle co_await. - (cp_parser_assignment_expression): Handle co_yield. - (cp_parser_statement): Handle RID_CO_RETURN. - (cp_parser_jump_statement): Handle co_return. - (cp_parser_operator): Handle co_await operator. - (cp_parser_yield_expression): New. - (cp_parser_required_error): Handle RT_CO_YIELD. - * pt.c (tsubst_copy): Handle CO_AWAIT_EXPR. - (tsubst_expr): Handle CO_AWAIT_EXPR, CO_YIELD_EXPR and - CO_RETURN_EXPRs. - * tree.c (cp_walk_subtrees): Likewise. + PR c++/98333 + * parser.c (cp_parser_class_specifier_1): Perform late-parsing + of NSDMIs before late-parsing of noexcept-specifiers. -2020-01-17 Jason Merrill <jason@redhat.com> +2021-01-19 Nathan Sidwell <nathan@acm.org> - PR c++/92531 - ICE with noexcept(lambda). - * pt.c (uses_template_parms): Don't try to enumerate all the - expression cases. + * module.cc (identifier): Merge overloads. -2020-01-17 Jakub Jelinek <jakub@redhat.com> +2021-01-19 Nathan Sidwell <nathan@acm.org> - PR c++/93228 - * parser.c (cp_parser_template_name): Look up deprecated attribute - in DECL_TEMPLATE_RESULT or its type's attributes. + PR c++/98624 + * module.cc (trees_out::write_location): Make static. -2020-01-16 Jason Merrill <jason@redhat.com> +2021-01-16 Kwok Cheung Yeung <kcy@codesourcery.com> - PR c++/93286 - ICE with __is_constructible and variadic template. - * pt.c (tsubst) [TREE_LIST]: Handle pack expansion. - (tsubst_copy_and_build) [TRAIT_EXPR]: Always use tsubst for type2. + * parser.c (cp_parser_omp_clause_detach): New. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH. + (OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_DETACH clause. + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_DETACH clause. + Prevent use of detach with mergeable and overriding the data sharing + mode of the event handle. - PR c++/93280 - ICE with aggregate assignment and DMI. - * init.c (get_nsdmi): Set TARGET_EXPR_DIRECT_INIT_P here. - * typeck2.c (digest_nsdmi_init): Not here. +2021-01-15 Nathan Sidwell <nathan@acm.org> -2020-01-15 Paolo Carlini <paolo.carlini@oracle.com> + PR c++/98538 + * tree.c (cp_build_qualified_type_real): Propagate an array's + dependentness to the copy, if known. - PR c++/91073 - * cp-tree.h (is_constrained_auto): New. - * parser.c (cp_parser_maybe_commit_to_declaration): Correctly - handle concept-check expressions; take a cp_decl_specifier_seq* - instead of a bool. - (cp_parser_condition): Update call. - (cp_parser_simple_declaration): Likewise. - (cp_parser_placeholder_type_specifier): Correctly handle - concept-check expressions. +2021-01-15 Jason Merrill <jason@redhat.com> -2020-01-15 Jason Merrill <jason@redhat.com> + PR c++/98642 + * call.c (unsafe_return_slot_p): Return int. + (init_by_return_slot_p): Split out from... + (unsafe_copy_elision_p): ...here. + (unsafe_copy_elision_p_opt): New name for old meaning. + (build_over_call): Adjust. + (make_safe_copy_elision): New. + * typeck2.c (split_nonconstant_init_1): Elide copy from safe + list-initialization. + * cp-tree.h: Adjust. - Revert - PR c++/33799 - destroy return value if local cleanup throws. - * cp-tree.h (current_retval_sentinel): New macro. - * decl.c (start_preparsed_function): Set up cleanup for retval. - * typeck.c (check_return_expr): Set current_retval_sentinel. +2021-01-15 Jason Merrill <jason@redhat.com> - PR c++/93257 - consteval void function. - * constexpr.c (verify_constant): Allow void_node. + * call.c (base_ctor_for, make_base_init_ok): New. + (build_over_call): Use make_base_init_ok. - PR c++/92871 - bad code with xvalue and GNU ?: extension. - * call.c (prevent_lifetime_extension): New. - (build_conditional_expr_1): Use it. +2021-01-15 Jason Merrill <jason@redhat.com> -2020-01-14 Nathan Sidwell <nathan@acm.org> + PR c++/63707 + * tree.c (build_vec_init_expr): Don't call build_vec_init_elt + if we got a CONSTRUCTOR. - PR c++/90916 - * pt.c (retrieve_specialization): Use get_template_info, not open - coding access. +2021-01-15 Nathan Sidwell <nathan@acm.org> - PR c++/90916 - * pt.c (retrieve_specialization): Get the TI from the decl or the - classtype as appropriate. + PR c++/98591 + * lang-specs.h: Fix handling of -fmodule-only with -fsyntax-only. -2020-01-14 David Malcolm <dmalcolm@redhat.com> +2021-01-14 Jason Merrill <jason@redhat.com> - * cp-gimplify.c (source_location_table_entry_hash::empty_zero_p): - New static constant. - * cp-tree.h (named_decl_hash::empty_zero_p): Likewise. - (struct named_label_hash::empty_zero_p): Likewise. - * decl2.c (mangled_decl_hash::empty_zero_p): Likewise. + * typeck2.c (process_init_constructor_record): Use fldtype + variable consistently. -2020-01-14 Jason Merrill <jason@redhat.com> +2021-01-14 Nathan Sidwell <nathan@acm.org> - PR c++/92590 - wrong handling of inherited default ctor. - * class.c (add_method): A constrained inherited ctor doesn't hide an - implicit derived ctor. - Revert: - PR c++/92552 - ICE with inherited constrained default ctor. - * pt.c (instantiate_class_template_1): Copy - TYPE_HAS_USER_CONSTRUCTOR. - PR c++/91930 - ICE with constrained inherited default ctor. - * name-lookup.c (do_class_using_decl): Set TYPE_HAS_USER_CONSTRUCTOR - for inherited constructor. - PR c++/92594 - ICE with inherited trivial default ctor. - * method.c (trivial_fn_p): Treat an inherited default constructor - like a normal default constructor. + PR c++/98372 + * tree.c (cp_tree_equal): Correct map_context logic. - PR c++/92594 - ICE with inherited trivial default ctor. - * method.c (trivial_fn_p): Treat an inherited default constructor - like a normal default constructor. +2021-01-13 Marek Polacek <polacek@redhat.com> - PR c++/92009 - ICE with punning of typeid. - * rtti.c (get_tinfo_desc): Call xref_basetypes. - * constexpr.c (cxx_fold_indirect_ref): Don't strip - REINTERPRET_CAST_P. + PR c++/98231 + * name-lookup.c (push_using_decl_bindings): New. + * name-lookup.h (push_using_decl_bindings): Declare. + * pt.c (tsubst_expr): Call push_using_decl_bindings. -2020-01-13 Jason Merrill <jason@redhat.com> +2021-01-13 Nathan Sidwell <nathan@acm.org> - PR c++/92746 - ICE with noexcept of function concept check. - * except.c (check_noexcept_r): Handle concept-check. + PR c++/98626 + * module.cc (module_add_import_initializers): Pass a + zero-element argument vector. - PR c++/92582 - ICE with member template as requirement. - * pt.c (struct find_template_parameter_info): Add ctx_parms. - (any_template_parm_r): Handle TEMPLATE_DECL. - (find_template_parameters): Take parms instead of their depth. - * constraint.cc (build_parameter_mapping): Pass them. +2021-01-12 Patrick Palka <ppalka@redhat.com> - PR c++/33799 - destroy return value if local cleanup throws. - * cp-tree.h (current_retval_sentinel): New macro. - * decl.c (start_preparsed_function): Set up cleanup for retval. - * typeck.c (check_return_expr): Set current_retval_sentinel. + PR c++/98611 + * tree.c (cp_walk_subtrees) <case TEMPLATE_TYPE_PARM>: Visit + the template of a CTAD placeholder. - PR c++/93238 - short right-shift with enum. - * typeck.c (cp_build_binary_op): Use folded op1 for short_shift. +2021-01-12 Marek Polacek <polacek@redhat.com> -2020-01-10 Jason Merrill <jason@redhat.com> + PR c++/98620 + * typeck2.c (process_init_constructor_record): Don't emit + -Wmissing-field-initializers warnings in unevaluated contexts. - * typeck.c (cp_build_binary_op): Restore short_shift code. +2021-01-11 Jakub Jelinek <jakub@redhat.com> - PR c++/93143 - incorrect tree sharing with constexpr. - * constexpr.c (cxx_eval_outermost_constant_expr): Don't assume - CONSTRUCTORs are already unshared. + PR c++/98481 + * class.c (find_abi_tags_r): Set *walk_subtrees to 2 instead of 1 + for types. + (mark_abi_tags_r): Likewise. + * decl2.c (min_vis_r): Likewise. + * tree.c (cp_walk_subtrees): If *walk_subtrees_p is 2, look through + typedefs. - PR c++/93173 - incorrect tree sharing. - PR c++/93033 - * cp-gimplify.c (cp_gimplify_init_expr, cp_gimplify_expr): Use - copy_if_shared after cp_genericize_tree. - * typeck2.c (split_nonconstant_init): Don't unshare here. +2021-01-08 Patrick Palka <ppalka@redhat.com> -2020-01-08 Jason Merrill <jason@redhat.com> + PR c++/98551 + * constexpr.c (cxx_eval_call_expression): Check CLASS_TYPE_P + instead of AGGREGATE_TYPE_P before calling replace_result_decl. - * cp-gimplify.c (cp_gimplify_expr) [TARGET_EXPR]: Check - TARGET_EXPR_DIRECT_INIT_P. - * constexpr.c (cxx_eval_constant_expression): Likewise. +2021-01-08 Patrick Palka <ppalka@redhat.com> -2020-01-08 Jason Merrill <jason@redhat.com> + PR c++/98515 + * semantics.c (check_accessibility_of_qualified_id): Punt if + we're checking access of a scoped non-static member inside a + class template. - PR c++/91369 - constexpr destructor and member initializer. - * constexpr.c (cxx_eval_store_expression): Look through TARGET_EXPR - when not preevaluating. +2021-01-07 Jakub Jelinek <jakub@redhat.com> -2020-01-08 Jason Merrill <jason@redhat.com> + PR c++/98329 + * pt.c (tsubst_copy) <case BIT_CAST_EXPR>: Don't call + cp_build_bit_cast here, instead just build_min a BIT_CAST_EXPR and set + its location. + (tsubst_copy_and_build): Handle BIT_CAST_EXPR. - * constexpr.c (cxx_eval_call_expression): Remove DECL_BY_REFERENCE - support. +2021-01-07 Marek Polacek <polacek@redhat.com> -2020-01-07 Paolo Carlini <paolo.carlini@oracle.com> + PR c++/98441 + * decl.c (grokdeclarator): Move the !funcdecl_p check inside the + !late_return_type block. - * init.c (build_new): Add location_t parameter and use it throughout. - (build_raw_new_expr): Likewise. - * parser.c (cp_parser_new_expression): Pass the combined_loc. - * pt.c (tsubst_copy_and_build): Adjust call. - * cp-tree.h: Update declarations. +2021-01-07 Jason Merrill <jason@redhat.com> -2020-01-07 Jason Merrill <jason@redhat.com> + * constexpr.c (cxx_bind_parameters_in_call): Add comment. + (cxx_eval_store_expression): Add comment. - PR c++/47877 - -fvisibility-inlines-hidden and member templates. - * decl2.c (determine_visibility): -fvisibility-inlines-hidden beats - explicit class visibility for a template. +2021-01-07 Jason Merrill <jason@redhat.com> -2020-01-07 Richard Sandiford <richard.sandiford@arm.com> + * call.c (has_next): Factor out from... + (next_conversion): ...here. + (strip_standard_conversion): And here. + (is_subseq): And here. + (build_conv): Check it. + (standard_conversion): Don't call build_conv + for ck_identity. - * mangle.c (mangle_type_attribute_p): New function, split out from... - (write_CV_qualifiers_for_type): ...here. Don't mangle attributes - that contain a space. +2021-01-06 Martin Sebor <msebor@redhat.com> -2020-01-07 Jakub Jelinek <jakub@redhat.com> + PR c++/95768 + * error.c (dump_expr): Call c_pretty_printer::unary_expression. - PR c++/91369 - * constexpr.c (struct constexpr_global_ctx): Add heap_alloc_count - member, initialize it to zero in ctor. - (cxx_eval_call_expression): Bump heap_dealloc_count when deleting - a heap object. Don't cache calls to functions which allocate some - heap objects and don't deallocate them or deallocate some heap - objects they didn't allocate. +2021-01-05 Patrick Palka <ppalka@redhat.com> -2020-01-06 Jason Merrill <jason@redhat.com> + * pt.c (unify) <case TEMPLATE_PARM_INDEX>: After walking into + the type of the NTTP, substitute into the type again. If the + type is still dependent, don't unify the NTTP. - PR c++/92552 - ICE with inherited constrained default ctor. - * pt.c (instantiate_class_template_1): Copy - TYPE_HAS_USER_CONSTRUCTOR. - * class.c (one_inherited_ctor): Don't set it here. +2021-01-05 Jakub Jelinek <jakub@redhat.com> -2020-01-06 Andrew Sutton <asutton@lock3software.com> + * Make-lang.in (cc1plus-checksum, cc1plus$(exeext): Add + $(CODYLIB) after $(BACKEND). - PR c++/92739 - parsing requires clause with attributes. - * parser.c (cp_parser_constraint_requires_parens): Exclude - attributes as postfix expressions. +2021-01-05 Jakub Jelinek <jakub@redhat.com> -2020-01-05 Jakub Jelinek <jakub@redhat.com> + PR c++/98469 + * constexpr.c (cxx_eval_constant_expression) <case BIT_CAST_EXPR>: + Punt if lval is true. + * semantics.c (cp_build_bit_cast): Call get_target_expr_sfinae on + the result if it has a class type. - PR c++/93138 - * parser.c (cp_parser_check_class_key): Disable access checks for the - simple name lookup. - (cp_parser_maybe_warn_enum_key): Likewise. Return early if - !warn_redundant_tags. +2021-01-05 Marek Polacek <polacek@redhat.com> -2010-01-05 Jakub Jelinek <jakub@redhat.com> + PR c++/82099 + * pt.c (resolve_overloaded_unification): Call + maybe_instantiate_noexcept after instantiating the function + decl. - PR c++/93046 - * cp-gimplify.c (cp_gimplify_init_expr): Don't look through - TARGET_EXPR if it has been gimplified already. +2021-01-05 Nathan Sidwell <nathan@acm.org> -2020-01-03 Jason Merrill <jason@redhat.com> + * parser.c (cp_parser_module_declaration): Alter diagnostic + text to say where is permissable. - PR c++/93033 - incorrect tree node sharing with array init. - * typeck2.c (split_nonconstant_init): Unshare non-decl. - * cp-gimplify.c (cp_gimplify_init_expr): Only split if -fexceptions. +2021-01-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> -2020-01-02 Jason Merrill <jason@redhat.com> + PR c++/98316 + * Make-lang.in (cc1plus$(exeext)): Add $(CODYLIB), $(NETLIBS). - * pt.c (invalid_nontype_parm_type_p): Reject class placeholder in - C++17. +2021-01-02 Jan Hubicka <jh@suse.cz> -2020-01-02 Jakub Jelinek <jakub@redhat.com> + * cp-tree.h (cp_tree_c_finish_parsing): Declare. + * decl2.c (c_parse_final_cleanups): Call cp_tree_c_finish_parsing. + * tree.c (cp_tree_c_finish_parsing): New function. - PR c/90677 - * cp-objcp-common.c (identifier_global_tag): Return NULL_TREE if name - has not been found, rather than error_mark_node. +2021-01-01 Jakub Jelinek <jakub@redhat.com> -2020-01-01 Jakub Jelinek <jakub@redhat.com> + * ChangeLog-2020: Rotate ChangeLog. New file. - Update copyright years. -Copyright (C) 2020 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/gcc/cp/ChangeLog-2020 b/gcc/cp/ChangeLog-2020 new file mode 100644 index 0000000..593627c --- /dev/null +++ b/gcc/cp/ChangeLog-2020 @@ -0,0 +1,6596 @@ +2020-12-24 Iain Sandoe <iain@sandoe.co.uk> + + * g++spec.c (LIBCXX, LIBCXX_PROFILE, LIBCXX_STATIC): New. + (LIBCXXABI, LIBCXXABI_PROFILE, LIBCXXABI_STATIC): New. + (enum stdcxxlib_kind): New. + (lang_specific_driver): Allow selection amongst multiple + c++ runtime libraries. + +2020-12-23 Nathan Sidwell <nathan@acm.org> + + PR c++/96045 + * parser.c (cp_lexer_new_main): Adjust EOF token location. + +2020-12-23 Jason Merrill <jason@redhat.com> + + PR c++/97597 + * class.c (is_empty_base_ref): New. + (build_base_path): Add NOP_EXPR after offset. + * cp-tree.h (is_empty_base_ref): Declare it. + * call.c (unsafe_return_slot_p): Call it. + +2020-12-23 Jakub Jelinek <jakub@redhat.com> + + PR c++/98353 + * init.c (build_zero_init_1): Use build_zero_cst for SCALAR_TYPE_P + zero initializers. + +2020-12-23 Jason Merrill <jason@redhat.com> + + PR c++/98332 + * constexpr.c (unshare_constructor): Check for NULL. + (cxx_eval_vec_init_1): Always exit early if non-constant. + +2020-12-22 Nathan Sidwell <nathan@acm.org> + + * module.cc (has_definition): Check DECL_LANG_SPECIFIC. + +2020-12-22 Jakub Jelinek <jakub@redhat.com> + + PR c++/93480 + * method.c (common_comparison_type): If comps[i] is a TREE_LIST, + use its TREE_VALUE instead. + (build_comparison_op): Handle array members. + +2020-12-22 Gerald Pfeifer <gerald@pfeifer.com> + + * module.cc (INCLUDE_STRING): Define. + (INCLUDE_VECTOR): Ditto. + +2020-12-22 Jason Merrill <jason@redhat.com> + + * mangle.c (write_member_name): Add assert. + (write_expression): Add asserts. + +2020-12-21 Nathan Sidwell <nathan@acm.org> + + * module.cc (create_dirs): Add logging. + (finish_module_processing): Unlink before rename. + +2020-12-21 Nathan Sidwell <nathan@acm.org> + + PR bootstrap/98412 + * mapper-client.cc: INCLUDE_STRING, INCLUDE_VECTOR. + (module_client::open_module_client): Avoid std::stoul. + * mapper-resolver.cc: INCLUDE_STRING, INCLUDE_VECTOR. + +2020-12-18 Kwok Cheung Yeung <kcy@codesourcery.com> + + * cp-lang.c (cxx_get_decl_init): New. + (cxx_omp_finish_decl_inits): New. + (LANG_HOOKS_GET_DECL_INIT): New. + (LANG_HOOKS_OMP_FINISH_DECL_INITS): New. + * cp-tree.h (dynamic_initializers): New. + * decl.c (dynamic_initializers): New. + * decl2.c (c_parse_final_cleanups): Add initializer entries + from vars to dynamic_initializers. + +2020-12-18 Nathan Sidwell <nathan@acm.org> + + * module.cc (O_CLOEXEC, O_BINARY): Add window's support. + (elf_in::defrost, module_state::do_import) + (finish_module_processing): Use O_BINARY. + +2020-12-18 Jakub Jelinek <jakub@redhat.com> + + PR c++/98343 + * cp-gimplify.c (source_location_table_entry_hash::pch_nx): Override + static member functions from ggc_remove. + +2020-12-18 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (satisfying_constraint): Move up definition + and give it bool type. + (failed_type_completion_count): Replace with ... + (failed_type_completions): ... this. + (note_failed_type_completion_for_satisfaction): Append the + supplied argument to failed_type_completions. + (some_type_complete_p): Define. + (sat_entry::maybe_unstable): Replace with ... + (sat_entry::ftc_begin, sat_entry::ftc_end): ... these. + (satisfaction_cache::ftc_count): Replace with ... + (satisfaction_cache::ftc_begin): ... this. + (satisfaction_cache::satisfaction_cache): Adjust accordingly. + (satisfaction_cache::get): Adjust accordingly, using + some_type_complete_p. + (satisfaction_cache::save): Adjust accordingly. + (satisfying_constraint_p): Remove unused function. + (satisfy_constraint): Set satisfying_constraint. + (satisfy_declaration_constraints): Likewise. + * decl.c (require_deduced_type): Call + note_failed_type_completion_for_satisfaction. + +2020-12-18 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (sat_entry::evaluating): New member. + (satisfaction_cache::get): If entry->evaluating, diagnose + self-recursive satisfaction. Otherwise, set entry->evaluating + if we're not reusing a cached satisfaction result. + (satisfaction_cache::save): Clear entry->evaluating. + (satisfy_atom): Set up diagnosing_failed_constraint before the + first call to get(). + +2020-12-18 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (failed_type_completion_count): New. + (note_failed_type_completion_for_satisfaction): New. + (sat_entry::constr): Rename to ... + (sat_entry::atom): ... this. + (sat_entry::location): New member. + (sat_entry::maybe_unstable): New member. + (sat_entry::diagnose_instability): New member. + (struct sat_hasher): Adjust after the above renaming. + (get_satisfaction, save_satisfaction): Remove. + (satisfaction_cache): Rewrite completely. + (satisfy_atom): When instantiation of the parameter mapping + fails, set diagnose_instability. Propagate location from + inst_cache.entry to cache.entry if the secondary lookup + succeeded. + (satisfy_declaration_constraints): When + failed_type_completion_count differs before and after + satisfaction, then don't cache the satisfaction result. + * cp-tree.h (note_failed_type_completion_for_satisfaction): + Declare. + * pt.c (tsubst) <case TYPENAME_TYPE>: Use + complete_type_or_maybe_complain instead of open-coding it. + * typeck.c (complete_type_or_maybe_complain): Call + note_failed_type_completion_for_satisfaction when type + completion fails. + +2020-12-17 Nathan Sidwell <nathan@acm.org> + + PR c++/98340 + * module.cc (uintset<T>::hash::add): Use uintset (0u).MEMBER, + rather than uintset::MEMBER. + +2020-12-17 Nathan Sidwell <nathan@acm.org> + + PR bootstrap/98300 + * module.cc: Fix ::read, ::write result signedness comparisons. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * mapper-resolver.cc: Remove early include of + sys/socket.h. Specify no CODY_NETWORKING instead. + * module.cc: Specify no CODY_NETWORKING. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_elaborated_type_specifier): Test + BOUND_TEMPLATE_TEMPLATE_PARM before checking for instantiation. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * module.cc (dumper::push): Clangify offsetof use. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * mapper-resolver.cc: #include sys/socket before system.h + due to poisoned bcopy use. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * module.cc (loc_spans): Make spans a pointer, not inline. + Adjust all accesses. + +2020-12-16 Nathan Sidwell <nathan@acm.org> + + * mapper-client.cc: Include sys/socket.h before system.h. + +2020-12-15 Patrick Palka <ppalka@redhat.com> + + * pt.c (in_template_function): Inspect cfun->decl instead of + current_function_decl. + +2020-12-15 Nathan Sidwell <nathan@acm.org> + + * module.cc: Replace stubs with implementation. + +2020-12-15 Nathan Sidwell <nathan@acm.org> + + * Make-lang.in (CXX_AND_OBJCXX_OBJS): Add mapper-client & + mapper-resolver. + * mapper-client.h: New. + * mapper-client.cc: New. + * mapper-resolver.cc: New. + +2020-12-15 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (do_namespace_alias): Set originating module + before pushing. + +2020-12-11 Jason Merrill <jason@redhat.com> + + PR libstdc++/97600 + * call.c (build_user_type_conversion_1): Avoid considering + conversion functions that return a clearly unsuitable type. + +2020-12-11 Jason Merrill <jason@redhat.com> + + * cp-tree.h (make_binding_vec): Add CXX_MEM_STAT_INFO. + +2020-12-11 Nathan Sidwell <nathan@acm.org> + + * config-lang.in (gtfiles): Add cp/module.cc. + * decl2.c (c_parse_final_cleanups): Add module support. + * lambda.c (record_lambda_scope): Call maybe_attach_decl. + * module.cc (maybe_attach_decl, lazy_load_specializations): Stubs. + (finish_module_procesing): Stub. + * pt.c (lookup_template_class_1): Lazy load specializations. + (instantiate_template_1): Likewise. + +2020-12-11 Nathan Sidwell <nathan@acm.org> + + * decl2.c (c_parse_final_cleanups): Refactor loop. + +2020-12-11 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (map_context_from, map_context_to): Declare. + * module.cc (map_context_from, map_context_to): Define. + * tree.c (cp_tree_equal): Check map_context_{from,to} for parm + context difference. Allow NON_LVALUE_EXPR and VIEW_CONVERT_EXPR + with null types. + +2020-12-11 Nathan Sidwell <nathan@acm.org> + + * cp-lang.c (LANG_HOOKS_PREPROCESS_MAIN_FILE): Override. + (LANG_HOOKS_PREPROCESS_OPTIONS): Override. + (LANG_HOOKS_PREPROCESS_TOKEN): Override. + * cp-objcp-common.c (cp_register_dumps): Add module dump. + (cp_handle_option): New. + * cp-objcp-common.h (cp_handle_option): Declare. + (LANG_HOOKS_HANDLE_OPTION): Override. + * cp-tree.h (module_dump_id): Declare. + * module.cc (module_dump_id): Define. + (module_begin_main_file, handle_module_option) + (module_preproces_options): Stubs. + +2020-12-11 Nathan Sidwell <nathan@acm.org> + + * module.cc (lazy_specializations_p): Stub. + * name-lookup.h (append_imported_binding_slot) + (mergeable_namespacE_slots, lookup_class_binding) + (walk_module_binding, import_module_binding, set_module_binding) + (note_pending_specializations, load_pending_specializations) + (add_module_decl, add_imported_namespace): Declare. + (get_cxx_dialect_name): Declare. + (enum WMB_flags): New. + * name-lookup.c (append_imported_binding_slot) + (mergeable_namespacE_slots, lookup_class_binding) + (walk_module_binding, import_module_binding, set_module_binding) + (note_pending_specializations, load_pending_specializations) + (add_module_decl, add_imported_namespace): New. + (get_cxx_dialect_name): Make extern. + +2020-12-11 Patrick Palka <ppalka@redhat.com> + + PR c++/78173 + * typeck.c (pointer_diff): Use complete_type_or_maybe_complain + instead of complete_type_or_else. + +2020-12-10 Jason Merrill <jason@redhat.com> + + * cp-tree.h (struct type_identity): New. + (make_temp_override): New. + * decl.c (grokdeclarator): Use it. + * except.c (maybe_noexcept_warning): Use it. + * parser.c (cp_parser_enum_specifier): Use it. + (cp_parser_parameter_declaration_clause): Use it. + (cp_parser_gnu_attributes_opt): Use it. + (cp_parser_std_attribute): Use it. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (do_nonmember_using_decl): Add INSERT_P parm. + Deal with exporting using decls. + (finish_nonmember_using_decl): Examine BINDING_VECTOR. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (visible_instantiation_path): Renamed. + * module.cc (get_originating_module_decl, lazy_load_binding) + (lazy_load_members, visible_instantiation_path): Stubs. + * name-lookup.c (STAT_TYPE_VISIBLE_P, STAT_VISIBLE): New. + (search_imported_binding_slot, init_global_partition) + (get_fixed_binding_slot): New. + (name_lookup::process_module_binding): New. + (name_lookup::search_namespace_only): Search BINDING_VECTOR. + (name_lookup::adl_namespace_fns): Likewise. + (name_lookip::search_adl): Search visible instantiation path. + (maybe_lazily_declare): Maybe lazy load members. + (implicitly_exporT_namespace): New. + (maybe_record_mergeable_decl): New. + (check_module_override): New. + (do_pushdecl): Deal with BINDING_VECTOR, check override. + (add_mergeable_namespace_entity): New. + (get_namespace_binding): Deal with BINDING_VECTOR. + (do_namespace_alias): Call set_originating_module. + (lookup_elaborated_type_1): Deal with BINDING_VECTOR. + (do_pushtag): Call set_originating_module. + (reuse_namespace): New. + (make_namespace_finish): Add FROM_IMPORT parm. + (push_namespace): Deal with BINDING_VECTOR & namespace reuse. + (maybe_save_operator_binding): Save when module CMI in play. + * name-lookup.h (add_mergeable_namespace_entity): Declare. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c: Include bitmap.h. + (enum binding_slots): New. + (maybe_add_fuzzy_binding): Return bool true if found. + (consider_binding_level): Add module support. + * module.cc (get_import_bitmap): Stub. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (pop_local_binding): Check for IDENTIFIER_ANON_P. + (update_binding): Level may be null, don't add namespaces to + level. + (newbinding_bookkeeping): New, broken out of ... + (do_pushdecl): ... here, call it. Don't push anonymous decls. + (pushdecl, add_using_namespace): Correct comments. + (do_push_nested_namespace): Remove assert. + (make_namespace, make_namespace_finish): New, broken out of ... + (push_namespace): ... here. Call them. Add namespace to level + here. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * error.c (dump_module_suffix): New. + (dump_aggr_type, dump_simple_decl, dump_function_name): Call it. + * ptree.c (cxx_print_decl): Print module information. + * module.cc (module_name, get_importing_module): Stubs. + +2020-12-10 Nathan Sidwell <nathan@acm.org> + + * name-lookup.h (set_class_bindings): Return vector, take signed + 'extra' parm. + * name-lookup.c (maybe_lazily_declare): Break out ... + (get_class_binding): .. of here, call it. + (find_member_slot): Adjust get_class_bindings call. + (set_class_bindings): Allow -ve extra. Return the vector. + (set_identifier_type_value_with_scope): Remove checking assert. + (lookup_using_decl): Set decl's context. + (do_pushtag): Adjust set_identifier_type_value_with_scope handling. + +2020-12-09 Nathan Sidwell <nathan@acm.org> + + * parser.h (struct cp_token): Add main_source_p field. + * parser.c (cp_lexer_new_main): Pass thought module token filter. + Check macros. + (cp_lexer_get_preprocessor_token): Set main_source_p. + (enum module_parse): New. + (cp_parser_diagnose_invalid_type_name): Deal with unrecognized + module-directives. + (cp_parser_skip_to_closing_parenthesize_1): Skip module-directivres. + (cp_parser_skip_to_end_of_statement): Likewise. + (cp_parser_skiup_to_end_of_block_or_statement): Likewise. + (cp_parser_translation_unit): Add module parsing calls. + (cp_parser_module_name, cp_parser_module_declaration): New. + (cp_parser_import_declaration, cp_parser_module_export): New. + (cp_parser_declaration): Add module export detection. + (cp_parser_template_declaration): Adjust 'export' error message. + (cp_parser_function_definition_after_declarator): Add + module-specific logic. + * module.cc (import_module, declare_module) + (maybe_check_all_macros): Stubs. + +2020-12-09 Marek Polacek <polacek@redhat.com> + + PR c++/97517 + * cxx-pretty-print.c (cxx_pretty_printer::simple_type_specifier): Handle + NULLPTR_TYPE. + (pp_cxx_type_specifier_seq): Likewise. + (cxx_pretty_printer::type_id): Likewise. + +2020-12-09 Nathan Sidwell <nathan@acm.org> + + * decl.c (duplicate_decls): Add module-specific redeclaration + logic. + (cxx_init_decl_processing): Export the global namespace, maybe + initialize modules. + (start_decl): Reject local-extern in a module, adjust linkage of + template var. + (xref_tag_1): Add module-specific redeclaration logic. + (start_enum): Likewise. + (finish_enum_value_list): Export unscoped members of an exported + enum. + (grokmethod): Implement p1779 linkage of in-class defined + functions. + * decl2.c (no_linkage_error): Imports are ok. + (c_parse_final_cleanups): Call fini_modules. + * lex.c (cxx_dup_lang_specific): Clear some module flags in the + copy. + * module.cc (module_kind): Define. + (module_may_redeclare, set_defining_module): Stubs. + (init_modules): Error on modules. + (fini_modules): Stub. + * rtti.c (push_abi_namespace): Save and reset module_kind. + (pop_abi_namespace): Restore module kind. + (build_dynamic_cast_1, tinfo_base_init): Adjust. + * semantics.c (begin_class_definition): Add module-specific logic. + (expand_or_defer_fn_1): Keep bodies of more fns when modules_p. + +2020-12-09 Tobias Burnus <tobias@codesourcery.com> + + * parser.c (cp_parser_omp_allocate): New. + (cp_parser_omp_construct, cp_parser_pragma): Call it. + +2020-12-09 Jason Merrill <jason@redhat.com> + + PR c++/98019 + * cvt.c (maybe_warn_nodiscard): Check c_inhibit_evaluation_warnings. + +2020-12-09 Jason Merrill <jason@redhat.com> + + PR c++/59238 + * init.c (expand_default_init): Pass tf_no_cleanup when building + a TARGET_EXPR to go on the RHS of an INIT_EXPR. + * typeck.c (cp_build_modify_expr): Likewise. + +2020-12-08 Marek Polacek <polacek@redhat.com> + + PR c++/98103 + * constexpr.c (cxx_eval_dynamic_cast_fn): If the evaluating of vtable + yields a null pointer, give an error and return. Use objtype. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * class.c (layout_class_type): Call set_instantiating_module. + (build_self_reference): Likewise. + * decl.c (grokfndecl): Call set_originating_module. + (grokvardecl): Likewise. + (grokdeclarator): Likewise. + * pt.c (maybe_new_partial_specialization): Call + set_instantiating_module, propagate DECL_MODULE_EXPORT_P. + (lookup_template_class_1): Likewise. + (tsubst_function_decl): Likewise. + (tsubst_decl, instantiate_template_1): Likewise. + (build_template_decl): Propagate module flags. + (tsubst_template_dcl): Likewise. + (finish_concept_definition): Call set_originating_module. + * module.cc (set_instantiating_module, set_originating_module): Stubs. + +2020-12-08 Jason Merrill <jason@redhat.com> + + PR c++/96299 + * cp-tree.h (build_new_op): Add overload that omits some parms. + (genericize_spaceship): Add location_t parm. + * constexpr.c (cxx_eval_binary_expression): Pass it. + * cp-gimplify.c (genericize_spaceship): Pass it. + * method.c (genericize_spaceship): Handle class-type arguments. + (build_comparison_op): Fall back to op</== when appropriate. + +2020-12-08 Jason Merrill <jason@redhat.com> + + * call.c (build_new_op_1): Set *overload for ambiguity. + (build_new_method_call_1): Likewise. + +2020-12-08 Bernd Edlinger <bernd.edlinger@hotmail.de> + + * decl2.c: (is_atomic_expensive_p): New helper function. + (build_atomic_load_byte): Rename to... + (build_atomic_load_type): ... and add new parameter type. + (get_guard_cond): Skip the atomic here if that is expensive. + Use the correct type for the atomic load on certain targets. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct tinst_level): Add path & visible fields. + (build_cdtor_clones): Declare. + (match_mergeable_specialization): Use a spec_entry, add insert parm. + * class.c (build_cdtor_clones): Externalize. + * pt.c (push_tinst_level_loc): Clear new fields. + (match_mergeable_specialization): Adjust API. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * decl2.c (start_objects): Refactor and adjust for named module + initializers. + (finish_objects): Likewise. + (generate_ctor_or_dtor_function): Likewise. + * module.cc (module_initializer_kind) + (module_add_import_initializers): Stubs. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * Make-lang.in (MODULE_VERSION): Override when DEVPHASE not empty. + * module.cc: Comment. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (mangle_module_substitution, mangle_identifier) + (mangle_module_global_init): Declare. + * mangle.c (struct globals): Add mod field. + (mangle_module_substitution, mangle_identifier) + (mangle_module_global_init): Define. + (write_module, maybe_write_module): New. + (write_name): Call it. + (start_mangling): Clear mod field. + (finish_mangling_internal): Adjust. + * module.cc (mangle_module, mangle_module_fini) + (get_originating_module): Stubs. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (module_token_pre, module_token_cdtor) + (module_token_lang): Declare. + * lex.c: Include langhooks. + (struct module_token_filter): New. + * cp-tree.h (module_token_pre, module_token_cdtor) + (module_token_lang): Define. + * module.cc (get_module, preprocess_module, preprocessed_module): + Nop stubs. + +2020-12-08 Nathan Sidwell <nathan@acm.org> + + * Make-lang.in (MODULE_VERSION): Define. + * module.cc: Add includes. + +2020-12-08 Jakub Jelinek <jakub@redhat.com> + + PR c++/98187 + * parser.c (cp_parser_omp_parallel): For parallel master with + -fopenmp-simd only, just call cp_parser_omp_master instead of + wrapping it in OMP_PARALLEL. + +2020-12-07 Marek Polacek <polacek@redhat.com> + + PR c++/98043 + * decl.c (pop_switch): If SWITCH_STMT_TYPE is a scoped enum type, + set it to the type of SWITCH_STMT_COND. + +2020-12-07 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (build_cplus_array_type): Add defaulted DEP parm. + * tree.c (set_array_type_common): Add DEP parm. + (build_cplus_array_type): Add DEP parm, determine dependency if + needed. Mark dependency of new types. + (cp_build_qualified_type_real): Adjust array-building call, assert + no surprising dependency. + (strip_typedefs): Likewise. + +2020-12-07 Nathan Sidwell <nathan@acm.org> + + PR c++/98116 + * typeck.c (structural_comptypes): Move early outs to comptype. + Always check template-alias match when comparing_specializations. + (comptypes): Do early out checking here. + +2020-12-05 Patrick Palka <ppalka@redhat.com> + + PR c++/97093 + * constraint.cc (parameter_mapping_equivalent_p): Add some + sanity checks. Clarify comment. + (tsubst_nested_requirement): Always perform satisfaction + quietly first. If that yields an erroneous result, emit a + context message and replay satisfaction noisily with the + diagnostic normal form. + (finish_nested_requirement): Normalize the constraint-expression + twice, once with diagnostic information and once without. Store + them in a TREE_LIST within the TREE_TYPE. + (diagnose_nested_requirement): When replaying satisfaction, use + the diagnostic normal form instead of renormalizing on the spot. + +2020-12-05 Patrick Palka <ppalka@redhat.com> + + PR c++/97093 + * constraint.cc (struct sat_info): Define. + (tsubst_nested_requirement): Pass a sat_info object to + satisfy_constraint. + (satisfy_constraint_r): Take a sat_info argument instead of + subst_info. + (satisfy_conjunction): Likewise. + (satisfy_disjunction): Likewise. Instead of first evaluating + each branch quietly, evaluate each branch only with + unsatisfaction diagnostics disabled. Exit early if evaluation + of a branch returns error_mark_node. + (satisfy_atom): Take a sat_info argument instead of subst_info. + Fix a comment. Check diagnose_unsatisfaction_p() instead of + noisy() before replaying a substitution failure. + (satisfy_constraint): Take a sat_info argument instead of + subst_info. + (satisfy_associated_constraints): Likewise. + (satisfy_constraint_expression): Likewise. + (satisfy_declaration_constraints): Likewise. + (constraint_satisfaction_value): Likewise and adjust + accordingly. Fix formatting. + (constraints_satisfied_p): Pass a sat_info object to + constraint_satisfaction_value. + (evaluate_concept_check): Pass a sat_info object to + satisfy_constraint_expression. + (diagnose_nested_requirement): Likewise. + (diagnose_constraints): Pass an appropriate sat_info object to + constraint_satisfaction_value. + +2020-12-05 Jakub Jelinek <jakub@redhat.com> + + PR c++/98122 + * constexpr.c (cxx_union_active_member): New function. + (cxx_fold_indirect_ref_1): Add ctx argument, pass it through to + recursive call. Handle UNION_TYPE. + (cxx_fold_indirect_ref): Add ctx argument, pass it to recursive calls + and cxx_fold_indirect_ref_1. + (cxx_eval_indirect_ref): Adjust cxx_fold_indirect_ref calls. + +2020-12-04 Jason Merrill <jason@redhat.com> + + PR c++/93083 + * pt.c (convert_template_argument): Handle equivalent placeholders. + (do_class_deduction): Look through EXPR_PACK_EXPANSION, too. + +2020-12-04 Jason Merrill <jason@redhat.com> + + * decl2.c (clear_consteval_vfns): Remove *. + * pt.c (do_auto_deduction): Remove *. + * parser.c (cp_parser_late_parsing_default_args): Change loop + to use range 'for'. + +2020-12-04 Nathan Sidwell <nathan@acm.org> + + PR c++/98116 + * cp-tree.h (comparing_typenames): Delete. + (cplus_build_array_type): Remove default parm. + * pt.c (comparing_typenames): Delete. + (spec_hasher::equal): Don't increment it. + * tree.c (set_array_type_canon): Remove dep parm. + (build_cplus_array_type): Remove dep parm changes. + (cp_build_qualified_type_real): Remove dependent array type + changes. + (strip_typedefs): Likewise. + * typeck.c (structural_comptypes): Revert comparing_typename + changes. + +2020-12-04 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h: Add various inline module state predicates, and + declare the API that will be provided by modules.cc + +2020-12-04 Jakub Jelinek <jakub@redhat.com> + + PR c++/80780 + * cp-gimplify.c (fold_builtin_source_location): Use 2 instead of 0 + as last argument to cxx_printable_name. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * cp-tree.h (releasing_vec::operator[]): Change parameter type to + ptrdiff_t. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (OVL_EXPORT): New. + (class ovl_iterator): Add get_using, exporting_p. + * tree.c (ovl_insert): Extend using_or_hidden meaning to include + an exported using. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_UNINSTANTIATED_TEMPLATE_FRIEND): New. + * pt.c (push_template_decl): Set it. + (tsubst_friend_function): Clear it. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (make_unbound_class_template_raw): Declare. + (canonical_type_parameter): Declare. + * decl.c (make_unbound_class_template_raw): Break out of ... + (make_unboud_class_template): ... here. Call it. + * pt.c (canonical_type_parameter): Externalize. Refactor & set + structural_equality for type parms. + +2020-12-03 Nathan Sidwell <nathan@acm.org> + + PR c++/98107 + * tree.c (build_cplus_array_type): Mark dependency of new variant. + (cp_build_qualified_type_real, strip_typedefs): Assert + TYPE_DEPENDENT_P_VALID, or not a dependent type. + +2020-12-03 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/93121 + * cp-tree.h (cp_build_bit_cast): Declare. + * cp-tree.def (BIT_CAST_EXPR): New tree code. + * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_BIT_CAST. + (cp_common_init_ts): Handle BIT_CAST_EXPR. + * cxx-pretty-print.c (cxx_pretty_printer::postfix_expression): + Likewise. + * parser.c (cp_parser_postfix_expression): Handle + RID_BUILTIN_BIT_CAST. + * semantics.c (cp_build_bit_cast): New function. + * tree.c (cp_tree_equal): Handle BIT_CAST_EXPR. + (cp_walk_subtrees): Likewise. + * pt.c (tsubst_copy): Likewise. + * constexpr.c (check_bit_cast_type, cxx_eval_bit_cast): New functions. + (cxx_eval_constant_expression): Handle BIT_CAST_EXPR. + (potential_constant_expression_1): Likewise. + * cp-gimplify.c (cp_genericize_r): Likewise. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * parser.c (cp_parser_primary_expression): Distinguish + parms from vars in error. + (cp_parser_late_parsing_default_args): Pushdecl parms + as we go. + +2020-12-03 Jason Merrill <jason@redhat.com> + + * name-lookup.c (begin_scope): Set immediate_fn_ctx_p. + * parser.c (cp_parser_late_parsing_default_args): Push + sk_function_parms scope. + +2020-12-03 Peter Bergner <bergner@linux.ibm.com> + + PR c++/97947 + * typeck2.c (digest_init_r): Handle OPAQUE_TYPE as an aggregate type. + +2020-12-02 Jakub Jelinek <jakub@redhat.com> + + PR c++/80780 + PR c++/93093 + * cp-tree.h (source_location_current_p): Declare. + * tree.c (source_location_current_p): New function. + * call.c (immediate_invocation_p): New function. + (build_over_call): Use it to resolve LWG3396. + * constexpr.c (cxx_eval_builtin_function_call): Temporarily set + current_function_decl from ctx->call->fundef->decl if any. + * cp-gimplify.c (cp_genericize_r) <case CALL_EXPR>: Fold calls + to immediate function std::source_location::current (). + +2020-12-02 Jason Merrill <jason@redhat.com> + + * decl.c (grokdeclarator): Improve diagnostic for + disallowed CTAD placeholder. + +2020-12-02 Jason Merrill <jason@redhat.com> + + * decl.c (check_initializer): Also look through STMT_EXPR + and BIND_EXPR. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (comparing_typenames): Declare. + * pt.c (comparing_typenames): Define. + (spec_hasher::equal): Increment it around comparisons. + * typeck.c (structural_comptypes): Adjust TYPENAME resolution + check. + +2020-12-02 Marek Polacek <polacek@redhat.com> + + PR c++/97975 + * constexpr.c (fold_non_dependent_init): Add a tree parameter. + Use it. + * cp-tree.h (fold_non_dependent_init): Add a tree parameter with + a default value. + * typeck2.c (store_init_value): Call fold_non_dependent_expr + only when checking the initializer for constexpr variables. + Call fold_non_dependent_init instead of maybe_constant_init. + +2020-12-02 Marek Polacek <polacek@redhat.com> + + PR c++/97187 + PR c++/97993 + * pt.c (tsubst_copy_and_build) <case NEW_EXPR>: Return error_mark_node + if init is erroneous. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_MODULE_PURVIEW_P, DECL_MODULE_IMPORT_P) + (DECL_MODULE_ENTITY_P): New. + (DECL_MODULE_PENDING_SPECIALIZATIONS_P): New. + (DECL_MODULE_PENDING_MEMBERS_P): New. + (DECL_MODULE_ATTACHMENTS_P): New. + (DECL_MODULE_EXPORT_P): New. + (struct lang_decl_base): Shrink sel field. Add new + module-specific fields. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_TINFO_P): Also for TYPE_DECLs. + (get_tinfo_decl_direct): Declare. + (get_pseudo_tinfo_index, get_pseudo_tinfo_type): Declare. + * rtti.c (get_tinfo_decl_direct): Externalize. + (get_tinfo_desc): Set DECL_TINFO_P on the typedef. + (get_pseudo_tinfo_index, get_pseudo_tinfo_type): New. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (maybe_add_lang_decl_raw, maybe_add_lang_type_raw): + Declare. + * lex.c (maybe_add_lang_decl_raw, maybe_add_lang_type_raw): + Externalize, reformat. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (build_cplus_array_type): Add defaulted DEP parm. + * tree.c (set_array_type_common): Add DEP parm. + (build_cplus_array_type): Add DEP parm, determine dependency if + needed. + (cp_build_qualified_type_real): Adjust array-building call. + (strip_typedefs): Likewise. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * ptree.c (cxx_print_xnode): Increase binding-vector prefix size. + +2020-12-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.def (BINDING_VECTOR): New. + * name-lookup.h (struct binding_slot): New. + (BINDING_VECTOR_SLOTS_PER_CLUSTER): New. + (struct binding_index, struct binding_cluster): New. + (BINDING_VECTOR_ALLOC_CLUSTERS, BINDING_VECTOR_CLUSTER_BASE) + (BINDING_VECTOR_CLUSTER): New. + (struct tree_binding_vec): New. + (BINDING_VECTOR_NAME, BINDING_VECTOR_GLOBAL_DUPS_P) + (BINDING_VECTOR_PARTITION_DUPS_P): New. + (BINDING_BINDING_GLOBAL_P, BINDING_BINDING_PARTITION_P): New. + (BINDING_VECTOR_PENDING_SPECIALIZATIONS) + (BINDING_VECTOR_PENDING_IS_HEADER_P) + (BINDING_VECTOR_PENDING_IS_PARTITION_P): New. + * cp-tree.h (enum cp_tree_node_structure_enum): Add + TS_CP_BINDING_VECTOR. + (union lang_tree_node): Add binding_vec field. + (make_binding_vec): Declare. + (named_decl_hash::hash, named_decl_hash::equal): Check for binding + vector. + * decl.c (cp_tree_node_structure): Add BINDING_VECTOR case. + * ptree.c (cxx_print_xnode): Add BINDING_VECTOR case. + * tree.c (make_binding_vec): New. + +2020-12-01 Ville Voutilainen <ville.voutilainen@gmail.com> + + PR c++/98054 + * cxx-pretty-print.c (pp_cxx_trait_expression): + Add support for __is_nothrow_{assignable,constructible}. + +2020-12-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/98072 + * parser.c (cp_parser_omp_depobj): Suppress location wrappers when + parsing depend clause. + +2020-12-01 Nathan Sidwell <nathan@acm.org> + + * lex.c (init_reswords): Maybe enable module keywords. + +2020-12-01 Nathan Sidwell <nathan@acm.org> + + * lang-specs.h: Add module-related options. + +2020-12-01 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_declaration): Add a not about where + attributes may be placed. + +2020-11-27 Martin Sebor <msebor@redhat.com> + + * error.c (add_quotes): Revert previous change and use pragma to + suppress -Wformat-diag. + +2020-11-26 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * g++spec.c (TIMELIB, TIME_LIBRARY): Remove. + (lang_specific_driver): Remove TIME_LIBRARY handling. + +2020-11-26 Thomas Schwinge <thomas@codesourcery.com> + + * parser.c (cp_parser_omp_var_list_no_open): Assert that array + section's 'low_bound', 'length' are not location wrapper nodes. + (cp_parser_oacc_all_clauses, cp_parser_oacc_cache): Instantiate + 'auto_suppress_location_wrappers'. + +2020-11-25 Martin Sebor <msebor@redhat.com> + + PR bootstrap/94982 + * constraint.cc (debug_argument_list): Avoid -Wformat-diag. + * error.c (function_category): Same. + (print_template_differences): Same. + * logic.cc (debug): Same. + * name-lookup.c (lookup_using_decl): Same. + * parser.c (maybe_add_cast_fixit): Same. + (cp_parser_template_introduction): Same. + * typeck.c (access_failure_info::add_fixit_hint): Same. + +2020-11-25 Thomas Schwinge <thomas@codesourcery.com> + + * pt.c (tsubst_omp_clauses): Handle 'OMP_CLAUSE__CACHE_'. + (tsubst_expr): Handle 'OACC_CACHE'. + +2020-11-24 Jason Merrill <jason@redhat.com> + + PR c++/97899 + * typeck2.c (store_init_value): Don't split_nonconstant_init in a + template. + +2020-11-24 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/96929 + * constexpr.c (cxx_eval_binary_expression): For shifts by constant + with MSB set, emulate older wide_int_binop behavior to preserve + diagnostics and -fpermissive behavior. + +2020-11-23 Nathan Sidwell <nathan@acm.org> + + * module.cc: New dummy file. + * Make-lang.in: Add rules to build module.o + +2020-11-23 Jozef Lawrynowicz <jozef.l@mittosystems.com> + + * decl.c (start_decl): Set DECL_INITIAL for initialized decls + before attribute processing. + +2020-11-23 Richard Sandiford <richard.sandiford@arm.com> + + PR c++/97904 + * pt.c (tsubst): Use verify_type_context to check the type + of an array element. + +2020-11-21 Marek Polacek <polacek@redhat.com> + + PR c++/94695 + * parser.c (warn_for_range_copy): Warn when the loop variable is + initialized with a value of a different type resulting in a copy. + +2020-11-21 Marek Polacek <polacek@redhat.com> + + PR c++/97846 + * constexpr.c (potential_constant_expression_1): Reject + LABEL_EXPRs that use non-artifical LABEL_DECLs. + +2020-11-21 Marek Polacek <polacek@redhat.com> + + PR c++/97881 + * parser.c (warn_about_ambiguous_parse): Only assume "int" if we + actually saw any type-specifiers. + +2020-11-21 Marek Polacek <polacek@redhat.com> + + PR c++/97839 + * parser.c (cp_parser_lambda_declarator_opt): Don't require (). + +2020-11-21 Marek Polacek <polacek@redhat.com> + + PR c++/97427 + * constexpr.c (cxx_set_object_constness): New function. + (cxx_eval_call_expression): Set new_obj for destructors too. + Call cxx_set_object_constness to set/unset TREE_READONLY of + the object under construction/destruction. + +2020-11-21 Aaron Sawdey <acsawdey@linux.ibm.com> + + * error.c (dump_type): Handle opaque types. + (dump_type_prefix): Handle opaque types. + (dump_type_suffix): Handle opaque types. + (dump_expr): Handle opaque types. + * pt.c (tsubst): Allow opaque types in templates. + (unify): Allow opaque types in templates. + * typeck.c (structural_comptypes): Handle comparison + of opaque types. + +2020-11-20 Jakub Jelinek <jakub@redhat.com> + + PR other/97911 + * Make-lang.in (c++.serial): Change from goal to a variable. + (.PHONY): Drop c++.serial and c++.prev. + (cc1plus$(exeext)): Depend on $(c++.serial) rather than c++.serial. + +2020-11-19 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct spec_entry): Moved from pt.c. + (walk_specializations, match_mergeable_specialization) + (get_mergeable_specialization_flags) + (add_mergeable_specialization): Declare. + * pt.c (struct spec_entry): Moved to cp-tree.h. + (walk_specializations, match_mergeable_specialization) + (get_mergeable_specialization_flags) + (add_mergeable_specialization): New. + +2020-11-19 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct constexpr_fundef): Moved from constexpr.c. + (maybe_save_constexpr_fundef): Declare. + (register_constexpr_fundef): Take constexpr_fundef object, return + void. + * decl.c (mabe_save_function_definition): Delete, functionality + moved to maybe_save_constexpr_fundef. + (emit_coro_helper, finish_function): Adjust. + * constexpr.c (struct constexpr_fundef): Moved to cp-tree.h. + (constexpr_fundef_hasher::equal): Constify. + (constexpr_fundef_hasher::hash): Constify. + (retrieve_constexpr_fundef): Make non-static. + (maybe_save_constexpr_fundef): Break out checking and duplication + from ... + (register_constexpr_fundef): ... here. Just register the constexpr. + +2020-11-19 Marek Polacek <polacek@redhat.com> + + PR c++/97523 + * init.c (build_new): When value-initializing an array new, + leave the INIT as an empty vector. + +2020-11-19 Marek Polacek <polacek@redhat.com> + + PR c++/97895 + * pt.c (do_auto_deduction): Don't crash when the constructor has + zero elements. + +2020-11-19 Nathan Sidwell <nathan@acm.org> + + PR c++/97905 + * decl.c (duplicate_decls): Relax new assert. + +2020-11-18 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_objc_valid_prefix_attributes): Check + for empty attributes. + +2020-11-18 Jakub Jelinek <jakub@redhat.com> + + * Make-lang.in (c++.serial): New goal. + (.PHONY): Add c++.serial c++.prev. + (cc1plus$(exeext)): Depend on c++.prev. Call LINK_PROGRESS. + +2020-11-17 Nathan Sidwell <nathan@acm.org> + + PR c++/97877 + * decl.c (duplicate_decls): Deal with duplicated DECL_LOCAL_DECL_P + decls. Extend decl_lang_specific checking assert. + +2020-11-17 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (enum cp_tree_index): Reorder to place lazy fields + after newly-added CPTI_MODULE_HWM. + +2020-11-17 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/97871 + * parser.c (cp_parser_declaration): Remove checking assert. + +2020-11-15 Jason Merrill <jason@redhat.com> + + * decl.c (cp_finish_decl): Only check abstractness on definition. + (require_complete_types_for_parms): Check abstractness here. + (create_array_type_for_decl): Not here. + (grokdeclarator, grokparms, complete_vars): Not here. + * pt.c (tsubst, tsubst_arg_types, tsubst_function_type): Not here. + * typeck2.c (struct pending_abstract_type): Remove. + (struct abstract_type_hasher): Remove. + (abstract_pending_vars, complete_type_check_abstract): Remove. + (abstract_virtuals_error_sfinae): Handle arrays. + * call.c (conv_is_prvalue): Split out from... + (conv_binds_ref_to_prvalue): ...here. + (implicit_conversion_1): Rename from implicit_conversion. + (implicit_conversion): An abstract prvalue is bad. + (convert_like_internal): Don't complain if expr is already + error_mark_node. + +2020-11-13 Jason Merrill <jason@redhat.com> + + * cp-tree.h (USING_DECL_UNRELATED_P): New. + (CONST_DECL_USING_P): New. + * class.c (handle_using_decl): If USING_DECL_UNRELATED_P, + clone the CONST_DECL. + * name-lookup.c (supplement_binding_1): A clone hides its + using-declaration. + (lookup_using_decl): Rewrite to separate lookup and validation. + (do_class_using_decl): Adjust. + (finish_nonmember_using_decl): Adjust. + * parser.c (make_location): Add cp_token overload. + (finish_using_decl): Split out from... + (cp_parser_using_declaration): ...here. Don't look through enums. + (cp_parser_using_enum): New. + (cp_parser_block_declaration): Call it. + (cp_parser_member_declaration): Call it. + * semantics.c (finish_id_expression_1): Handle enumerator + used from class scope. + +2020-11-13 Vladimir N. Makarov <vmakarov@redhat.com> + + * parser.c (cp_parser_asm_definition): Parse outputs for asm + goto too. + +2020-11-13 Iain Sandoe <iain@sandoe.co.uk> + + PR objc/77404 + * parser.c (cp_parser_objc_class_interface): Pass the + location of the class name to the interface declaration. + +2020-11-13 Patrick Palka <ppalka@redhat.com> + + * semantics.c (finish_compound_literal): Don't wrap the original + compound literal in a TARGET_EXPR when inside a template. + +2020-11-12 Jakub Jelinek <jakub@redhat.com> + + PR c++/97790 + * constexpr.c (cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR, + case TRY_FINALLY_EXPR, case CLEANUP_STMT>: Don't pass jump_target to + cxx_eval_constant_expression when evaluating the cleanups. + +2020-11-11 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_declaration): Unless we are compiling for + Ojective-C++, warn about and discard any attributes that prefix + a linkage specification. + +2020-11-11 Patrick Palka <ppalka@redhat.com> + + PR c++/88115 + * mangle.c (write_expression): Mangle __alignof_ differently + from alignof when the ABI version is at least 15. + +2020-11-11 Patrick Palka <ppalka@redhat.com> + + PR c++/88115 + * cp-tree.h (cxx_sizeof_or_alignof_expr): Add bool parameter. + * decl.c (fold_sizeof_expr): Pass false to + cxx_sizeof_or_alignof_expr. + * parser.c (cp_parser_unary_expression): Pass std_alignof to + cxx_sizeof_or_alignof_expr. + * pt.c (tsubst_copy): Pass false to cxx_sizeof_or_alignof_expr. + (tsubst_copy_and_build): Pass std_alignof to + cxx_sizeof_or_alignof_expr. + * typeck.c (cxx_alignof_expr): Add std_alignof bool parameter + and pass it to cxx_sizeof_or_alignof_type. Set ALIGNOF_EXPR_STD_P + appropriately. + (cxx_sizeof_or_alignof_expr): Add std_alignof bool parameter + and pass it to cxx_alignof_expr. Assert op is either + SIZEOF_EXPR or ALIGNOF_EXPR. + +2020-11-11 Marek Polacek <polacek@redhat.com> + + PR c++/97518 + * pt.c (tsubst_qualified_id): Use EXPR_LOCATION of the qualified-id. + Use it to maybe_wrap_with_location the final expression. + +2020-11-10 Marek Polacek <polacek@redhat.com> + + PR c++/97518 + * cp-tree.h (finish_static_assert): Adjust declaration. + * parser.c (cp_parser_static_assert): Pass false to + finish_static_assert. + * pt.c (tsubst_expr): Pass true to finish_static_assert. + * semantics.c (find_failing_clause_r): New function. + (find_failing_clause): New function. + (finish_static_assert): Add a bool parameter. Use + iloc_sentinel. Call contextual_conv_bool instead of + perform_implicit_conversion_flags. Don't check for INTEGER_CST before + calling integer_zerop. Call find_failing_clause and maybe use its + location. Print the original condition or the failing clause if + SHOW_EXPR_P. + +2020-11-10 Strager Neds <strager.nds@gmail.com> + + * decl.c (duplicate_decls): Use new overload of + set_decl_section_name. + * method.c (use_thunk): Same. + * optimize.c (maybe_clone_body): Same. + * coroutines.cc (act_des_fn): Same. + +2020-11-10 Jakub Jelinek <jakub@redhat.com> + + PR c/97748 + * cvt.c (convert_to_void): Check (complain & tf_warning) in the outer + if rather than twice times in the inner one. Use warn_if_unused_value. + Formatting fix. + +2020-11-10 Chung-Lin Tang <cltang@codesourcery.com> + + * parser.c (cp_parser_omp_target_data): Add use of + new c_omp_adjust_map_clauses function. Add GOMP_MAP_ATTACH_DETACH as + handled map clause kind. + (cp_parser_omp_target_enter_data): Likewise. + (cp_parser_omp_target_exit_data): Likewise. + (cp_parser_omp_target): Likewise. + * semantics.c (handle_omp_array_sections): Adjust COMPONENT_REF case to + use GOMP_MAP_ATTACH_DETACH map kind for C_ORT_OMP region type. Fix + interaction between reference case and attach/detach. + (finish_omp_clauses): Adjust bitmap checks to allow struct decl and + same struct field access to co-exist on OpenMP construct. + +2020-11-09 Marek Polacek <polacek@redhat.com> + + DR 1914 + * parser.c (cp_parser_check_std_attribute): Return bool. Add a + location_t parameter. Return true if the attribute wasn't duplicated. + Give a warning instead of an error. Check more attributes. + (cp_parser_std_attribute_list): Don't add duplicated attributes to + the list. Pass location to cp_parser_check_std_attribute. + +2020-11-09 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (norm_info::norm_info): Initialize orig_decl. + (norm_info::orig_decl): New data member. + (normalize_atom): When caching an atom for the first time, + compute a list of template parameters used in the targets of the + parameter mapping and store it in the TREE_TYPE of the mapping. + (get_normalized_constraints_from_decl): Set current_function_decl + appropriately when normalizing. As an optimization, don't + set up a push_nested_class_guard when decl has no constraints. + (sat_hasher::hash): Use this list to hash only the template + arguments that are relevant to the atom. + (satisfy_atom): Use this list to compare only the template + arguments that are relevant to the atom. + * pt.c (keep_template_parm): Do a sanity check on the parameter's + index when flag_checking. + +2020-11-09 Patrick Palka <ppalka@redhat.com> + + * cp-tree.h (ATOMIC_CONSTR_MAP_INSTANTIATED_P): Define this flag + for ATOMIC_CONSTRs. + * constraint.cc (sat_hasher::hash): Use hash_atomic_constraint + if the flag is set, otherwise keep using a pointer hash. + (sat_hasher::equal): Return false if the flag's setting differs + on two atoms. Call atomic_constraints_identical_p if the flag + is set, otherwise keep using a pointer equality test. + (satisfy_atom): After instantiating the parameter mapping, form + another ATOMIC_CONSTR using the instantiated mapping and query + the cache again. Cache the satisfaction value of both atoms. + (diagnose_atomic_constraint): Simplify now that the supplied + atom has an instantiated mapping. + +2020-11-09 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (atom_cache): Define this deletable hash_table. + (normalize_atom): Use it to cache ATOMIC_CONSTRs when not + generating diagnostics. + (sat_hasher::hash): Use htab_hash_pointer instead of + hash_atomic_constraint. + (sat_hasher::equal): Test for pointer equality instead of + atomic_constraints_identical_p. + * cp-tree.h (struct atom_hasher): Moved and renamed from ... + * logic.cc (struct constraint_hash): ... here. + (clause::m_set): Adjust accordingly. + +2020-11-09 Patrick Palka <ppalka@redhat.com> + + PR c++/93907 + * constraint.cc (tsubst_parameter_mapping): Also canonicalize + the type arguments of a TYPE_ARGUMENT_PACk. + +2020-11-09 Jason Merrill <jason@redhat.com> + + * pt.c (tsubst): Replace *_ARGUMENT_PACK code with + a call to tsubst_argument_pack. + +2020-11-09 Jason Merrill <jason@redhat.com> + + * class.c (handle_using_decl): Add an iloc_sentinel. + +2020-11-09 Marek Polacek <polacek@redhat.com> + + PR c++/97762 + * parser.c (warn_about_ambiguous_parse): Handle the case when + there is no type in the decl-specifiers. + +2020-11-09 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (LOOKUP_FOUND_P): Add ENUMERAL_TYPE. + * name-lookup.c (class name_lookup): Add comments. + (name_lookup::adl_namespace_only): Replace with ... + (name_lookup::adl_class_fns): ... this and ... + (name_lookup::adl_namespace_fns): ... this. + (name_lookup::adl_namespace): Deal with inline nests here. + (name_lookup::adl_class): Complete the type here. + (name_lookup::adl_type): Call broken-out enum .. + (name_lookup::adl_enum): New. No need to call the namespace adl + if it is class-scope. + (name_lookup::search_adl): Iterate over collected scopes here. + +2020-11-09 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (lookup_qualified_name): Expose an overload of a + singleton with known type. + (lookup_name_1): Just check the overload's type to expose it. + * parser.c (cp_parser_lookup_name): Do not do that check here. + +2020-11-08 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_objc_at_property_declaration): Handle + class keywords in @property attribute context. + +2020-11-06 Marek Polacek <polacek@redhat.com> + + PR c++/81660 + * except.c (can_convert_eh): Change the return type to bool. If + the type TO and FROM are the same, return true. + +2020-11-06 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_objc_at_property_declaration): + Improve parsing fidelity. Associate better location info + with @property attributes. Clean up the interface to + objc_add_property_declaration (). + +2020-11-06 Jakub Jelinek <jakub@redhat.com> + + PR c++/67453 + * decl.c (duplicate_decls): Propagate DECL_ATTRIBUTES and + DECL_PRESERVE_P from olddecl to its clones if any. + +2020-11-06 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_UNDECLARED_BUILTIN_P): Delete. + * cp-objcp-common.c (names_bultin_p): Rename + DECL_IS_BUILTIN->DECL_IS_UNDECLARED_BUILTIN. + * decl.c (decls_match): Likewise. Replace + DECL_UNDECLARED_BUILTIN_P with DECL_IS_UNDECLARED_BUILTIN. + (duplicate_decls): Likewise. + * decl2.c (collect_source_refs): Likewise. + * name-lookup.c (anticipated_builtin_p, print_binding_level) + (do_nonmember_using_decl): Likewise. + * pt.c (builtin_pack_fn_p): Likewise. + * typeck.c (error_args_num): Likewise. + +2020-11-06 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_template_declaration): Adjust 'export' warning. + (cp_parser_explicit_specialization): Remove unneeded bool setting. + +2020-11-06 Jan Hubicka <jh@suse.cz> + + * tree.c (cp_fix_function_decl_p): Do not access ipa_ref_list dirrectly. + +2020-11-06 Tobias Burnus <tobias@codesourcery.com> + + * parser.c (cp_parser_omp_atomic): Add openacc parameter and update + OpenACC matching. + (cp_parser_omp_construct): Update call. + +2020-11-05 Marek Polacek <polacek@redhat.com> + + * except.c (check_handlers_1): Add auto_diagnostic_group. + +2020-11-05 Marek Polacek <polacek@redhat.com> + + PR c++/78209 + * pt.c (do_auto_deduction): If init is REFERENCE_REF_P, use its + first operand. + +2020-11-05 Marek Polacek <polacek@redhat.com> + + PR c++/97675 + * except.c (check_handlers_1): Use OPT_Wexceptions for the + warning. Use inform for the second part of the warning. + +2020-11-05 Marek Polacek <polacek@redhat.com> + + PR c++/25814 + * cp-tree.h (enum cp_tree_index): Add CPTI_EXPLICIT_VOID_LIST. + (explicit_void_list_node): Define. + (PARENTHESIZED_LIST_P): New macro. + (struct cp_declarator): Add function::parens_loc. + * decl.c (cxx_init_decl_processing): Initialize explicit_void_list_node. + (grokparms): Also break when explicit_void_list_node. + * parser.c (make_call_declarator): New location_t parameter. Use it + to set declarator->u.function.parens_loc. + (cp_parser_lambda_declarator_opt): Pass UNKNOWN_LOCATION to + make_call_declarator. + (warn_about_ambiguous_parse): New function. + (cp_parser_init_declarator): Call warn_about_ambiguous_parse. + (cp_parser_declarator): Set *parenthesized_p to false rather than to + true. + (cp_parser_direct_declarator): Create a location for the function's + parentheses and pass it to make_call_declarator. + (cp_parser_parameter_declaration_clause): Return explicit_void_list_node + for (void). + (cp_parser_parameter_declaration_list): Set PARENTHESIZED_LIST_P + in the parameters tree. + +2020-11-04 Jakub Jelinek <jakub@redhat.com> + + PR c++/97670 + * semantics.c (finish_omp_clauses): Look through array reductions to + find underlying decl to clear in the aligned_head bitmap. Use + DECL_UID (t) instead of DECL_UID (OMP_CLAUSE_DECL (c)) when clearing + in the bitmap. Only diagnose errors about allocate vars not being + privatized on the same construct on allocate clause if it has + a DECL_P OMP_CLAUSE_DECL. + +2020-11-04 Iain Sandoe <iain@sandoe.co.uk> + + * constexpr.c (potential_constant_expression_1): Handle + expressions known to be non-constant for Objective-C. + +2020-11-03 Jason Merrill <jason@redhat.com> + + * tree.c (is_byte_access_type): Don't use char_type_p. + +2020-11-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/97663 + * parser.c (cp_parser_init_declarator): Don't try to parse + C++17 deduction guides if there are any type specifiers even when + type is NULL. + +2020-11-03 Kamlesh Kumar <kamleshbhalui@gmail.com> + Jason Merrill <jason@redhat.com> + + PR c++/97453 + DR2303 + * pt.c (get_template_base): Consider closest base in template + deduction when base of base also matches. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * pt.c (tsubst_expr): Simplify using decl instantiation, add + asserts. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * class.c (copy_fndecl_with_name): Always not top level. + (build_cdtor_clones): Add update_methods parm, use it to + conditionally update the method vec. Return void + (clone_cdtor): Adjust. + (clone_constructors_and_destructors): Adjust comment. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * pt.c (primary_template_specialization_p): Use + VAR_OR_FUNCTION_DECL_P. + (tsubst_template_decl): Check for FUNCTION_DECL, not !TYPE && !VAR + for registering a specialization. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (fixup_deferred_exception_variants): Declare. + * parser.c (cp_parser_class_specifier_1): Call it when + completing deferred parses rather than creating a variant. + (cp_parser_member_declaration): Move comment from ... + (cp_parser_noexcept_specification_opt): ... here. Refactor the + deferred parse. + * tree.c (fixup_deferred_exception_variants): New. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * pt.c (tsubst_lambda_expr): Reorder extra-scope handling to match + the non-template case. + (instantiate_body): Move a couple of declarations to their + initializers. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * decl.c (duplicate_decls): Return error_mark_node fo extern-c + mismatch. + +2020-11-03 Marek Polacek <polacek@redhat.com> + + * constexpr.c (potential_constant_expression_1): Treat + __PRETTY_FUNCTION__ inside a template function as + potentially-constant. + * pt.c (uses_template_parms): Call + instantiation_dependent_expression_p instead of + value_dependent_expression_p. + (instantiation_dependent_expression_p): Check + potential_constant_expression before calling + value_dependent_expression_p. + +2020-11-03 Marek Polacek <polacek@redhat.com> + + PR c++/97632 + * init.c (build_new_1): Disable -Winit-list-lifetime for an unevaluated + operand. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * tree.c (bind_template_template_parm): Mark the parm as a + template parm. + (cp_tree_equal): Refactor CALL_EXPR. Use comp_template_args for + TREE_VECs. + +2020-11-03 Nathan Sidwell <nathan@acm.org> + + * rtti.c (init_rtti_processing): Move var decl to its init. + (get_tinfo_decl): Likewise. Break out creation to called helper + ... + (get_tinfo_decl_direct): ... here. + (build_dynamic_cast_1): Move var decls to their initializers. + (tinfo_base_init): Set decl's location to BUILTINS_LOCATION. + (get_tinfo_desc): Only push ABI namespace when needed. Set type's + context. + +2020-11-02 Nathan Sidwell <nathan@acm.org> + + * decl.c (start_decl_1): Refactor declarations. Fixup some + whitespace. + (lookup_and_check_tag): Fixup some whitespace. + +2020-11-02 Nathan Sidwell <nathan@acm.org> + + * decl.c (duplicate_decls): Refactor some template & builtin + handling. + +2020-11-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct cxx_int_tree_map): Delete. + (struct cxx_int_tree_map_hasher): Delete. + * cp-gimplify.c (cxx_int_tree_map_hasher::equal): Delete. + (cxx_int_tree_map_hasher::hash): Delete. + +2020-11-02 Patrick Palka <ppalka@redhat.com> + + * class.c (finish_struct_1): Don't call clear_satisfaction_cache. + * constexpr.c (clear_cv_and_fold_caches): Likewise. Remove bool + parameter. + * constraint.cc (clear_satisfaction_cache): Remove definition. + * cp-tree.h (clear_satisfaction_cache): Remove declaration. + (clear_cv_and_fold_caches): Remove bool parameter. + * typeck2.c (store_init_value): Remove argument to + clear_cv_and_fold_caches. + +2020-11-01 Iain Sandoe <iain@sandoe.co.uk> + + * parser.c (cp_parser_objc_at_property_declaration): Use any + exisiting syntax error to suppress complaints about a missing + closing parenthesis in parsing property attributes. + +2020-10-30 Jakub Jelinek <jakub@redhat.com> + + * semantics.c (finish_omp_clauses) <case OMP_CLAUSE_ALLOCATE>: Handle + non-static members in methods. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_ALLOCATE. + +2020-10-29 Marek Polacek <polacek@redhat.com> + + DR 625 + PR c++/97479 + * parser.c (cp_parser_type_id_1): Reject using auto as + a template-argument in C++20. + +2020-10-29 Marek Polacek <polacek@redhat.com> + + PR c++/93107 + * pt.c (do_auto_deduction): Call resolve_nondeduced_context for + the elements of a { } list. + +2020-10-29 Marek Polacek <polacek@redhat.com> + + * typeck.c (do_warn_enum_conversions): Don't warn for SPACESHIP_EXPR. + (cp_build_binary_op): Reject float <=> enum or enum <=> float. Use + CP_INTEGRAL_TYPE_P instead of INTEGRAL_OR_ENUMERATION_TYPE_P. + +2020-10-29 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (get_normalized_constraints): Remove 'args' + parameter. Pass NULL_TREE as the initial template arguments to + normalize_expression. + (get_normalized_constraints_from_info): Remove 'args' parameter + and adjust the call to get_normalized_constraints. + (get_normalized_constraints_from_decl): Remove 'args' local + variable and adjust call to get_normalized_constraints_from_info. + (normalize_concept_definition): Remove 'args' local variable + and adjust call to get_normalized_constraints. + (normalize_constraint_expression): Remove the two-parameter + overload. Remove 'args' parameter from the three-parameter + overload and update function comment accordingly. Remove + default argument from 'diag' parameter. Adjust call to + get_normalized_constraints. + (finish_nested_requirement): Adjust call to + normalize_constraint_expression. + (strictly_subsumes): Remove 'args' parameter. Adjust call to + get_normalized_constraints_from_info. + (weakly_subsumes): Likewise. + * cp-tree.h (strictly_subsumes): Remove 'args' parameter. + (weakly_subsumes): Likewise. + * pt.c (process_partial_specialization): Adjust call to + strictly_subsumes. + (is_compatible_template_arg): Adjust call to weakly_subsumes. + +2020-10-29 Patrick Palka <ppalka@redhat.com> + + PR c++/97412 + * constraint.cc (normalize_concept_check): Don't call + tsubst_template_args when 'args' is NULL. + +2020-10-29 Jason Merrill <jason@redhat.com> + + PR c++/97388 + * constexpr.c (cxx_eval_outermost_constant_expr): Revert to + original expression if evaluation sets non_constant_p. + +2020-10-29 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/97388 + * constexpr.c (cxx_bind_parameters_in_call): Set non_constant_args + if the parameter type has a non-trivial destructor. + (cxx_eval_call_expression): Only unshare arguments if we're + memoizing this evaluation. + +2020-10-29 Jakub Jelinek <jakub@redhat.com> + + PR c++/95808 + * cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_VEC_UNINIT_IDENTIFIER + and CPTI_HEAP_VEC_IDENTIFIER. + (heap_vec_uninit_identifier, heap_vec_identifier): Define. + * decl.c (initialize_predefined_identifiers): Initialize those + identifiers. + * constexpr.c (cxx_eval_call_expression): Reject array allocations + deallocated with non-array deallocation or non-array allocations + deallocated with array deallocation. + (non_const_var_error): Handle heap_vec_uninit_identifier and + heap_vec_identifier too. + (cxx_eval_constant_expression): Handle also heap_vec_uninit_identifier + and in that case during initialization replace it with + heap_vec_identifier. + (find_heap_var_refs): Handle heap_vec_uninit_identifier and + heap_vec_identifier too. + +2020-10-29 Nathan Sidwell <nathan@acm.org> + + * pt.c (push_template_decl): Do not give function-scope entities + other than implicit typedefs a template header. Do not readd + template info to a redeclared template. + +2020-10-28 Marek Polacek <polacek@redhat.com> + + * decl.c (grokdeclarator): Offer a fix-it hint for the "unnecessary + parentheses in declaration" warning. + * parser.c (cp_parser_direct_declarator): When setting + declarator->parenthesized, use a location range. + +2020-10-28 Marek Polacek <polacek@redhat.com> + + PR c++/97573 + * call.c (build_conditional_expr_1): Warn about the deprecated + enum/real type conversion in C++20. Also warn about a non-enumerated + and enumerated type in ?: when -Wenum-conversion is on. + * typeck.c (do_warn_enum_conversions): New function. + (cp_build_binary_op): Call it. + +2020-10-28 Marek Polacek <polacek@redhat.com> + + PR c++/96675 + PR c++/96742 + * pt.c (tsubst_copy_and_build): Call value_dependent_expression_p or + type_dependent_expression_p instead of type_dependent_expression_p_push. + But only call value_dependent_expression_p for expressions that are + potential_constant_expression. + +2020-10-28 Marek Polacek <polacek@redhat.com> + + PR c++/94799 + * parser.c (cp_parser_class_name): Use parser->scope when + setting typename_p. + +2020-10-28 Marek Polacek <polacek@redhat.com> + + PR c++/86773 + * parser.c (cp_parser_fold_expression): Return error_mark_node + if a left fold is preceded by an expression. + +2020-10-28 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_omp_declare_reduction): Set + DECL_LOCAL_DECL_P before push_template_decl. + * pt.c (instantiate_body): Nested fns do not have template_info. + +2020-10-28 Patrick Palka <ppalka@redhat.com> + + PR c++/95132 + * decl2.c (mark_used): Move up the constraints_satisfied_p check + so that we check constraints before calling maybe_instantiate_decl. + +2020-10-28 Nathan Sidwell <nathan@acm.org> + + * pt.c (push_template_decl): Refactor for some RAII. + +2020-10-28 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_name): Handle allocate. + (cp_parser_omp_clause_allocate): New function. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_ALLOCATE. + (OMP_FOR_CLAUSE_MASK, OMP_SECTIONS_CLAUSE_MASK, + OMP_PARALLEL_CLAUSE_MASK, OMP_SINGLE_CLAUSE_MASK, + OMP_TASK_CLAUSE_MASK, OMP_TASKGROUP_CLAUSE_MASK, + OMP_DISTRIBUTE_CLAUSE_MASK, OMP_TEAMS_CLAUSE_MASK, + OMP_TARGET_CLAUSE_MASK, OMP_TASKLOOP_CLAUSE_MASK): Add + PRAGMA_OMP_CLAUSE_ALLOCATE. + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_ALLOCATE. + * pt.c (tsubst_omp_clauses): Likewise. + +2020-10-27 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct lang_type): Delete nested_udts field. + (CLASSTYPE_NESTED_UTDS): Delete. + * name-lookup.h (binding_table, binding_entry): Delete typedefs. + (bt_foreach_proc): Likewise. + (struct binding_entry_s): Delete. + (SCOPE_DEFAULT_HT_SIZE, CLASS_SCOPE_HT_SIZE) + (NAMESPACE_ORDINARY_HT_SIZE, NAMESPACE_STD_HT_SIZE) + (GLOBAL_SCOPE_HT_SIZE): Delete. + (binding_table_foreach, binding_table_find): Delete declarations. + * name-lookup.c (ENTRY_INDEX): Delete. + (free_binding_entry): Delete. + (binding_entry_make, binding_entry_free): Delete. + (struct binding_table_s): Delete. + (binding_table_construct, binding_table_free): Delete. + (binding_table_new, binding_table_expand): Delete. + (binding_table_insert, binding_table_find): Delete. + (binding_table_foreach): Delete. + (maybe_process_template_type_declaration): Delete + CLASSTYPE_NESTED_UTDS insertion. + (do_pushtag): Likewise. + * decl2.c (bt_reset_linkage_1): Fold into reset_type_linkage_1. + (reset_type_linkage_2, bt_reset_linkage_2): Fold into + reset_type_linkage. + * pt.c (instantiate_class_template_1): Delete NESTED_UTDs comment. + (bt_instantiate_type_proc): Delete. + (do_type_instantiation): Instantiate implicit typedef fields. + Delete NESTED_UTD walk. + * search.c (lookup_field_r): Delete unreachable NESTED_UTD + search. + +2020-10-27 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_explicit_instantiation): Refactor some RAII. + * pt.c (bt_instantiate_type_proc): DATA is the tree, pass type to + do_type_instantiation. + (do_type_instantiation): Require T to be a type. Refactor for + some RAII. + +2020-10-26 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-tree.h (CPTK_IS_NOTHROW_ASSIGNABLE): New. + (CPTK_IS_NOTHROW_CONSTRUCTIBLE): Likewise. + (is_nothrow_xible): Likewise. + * method.c (is_nothrow_xible): New. + (is_trivially_xible): Tweak. + * parser.c (cp_parser_primary_expression): Handle the new RID_*. + (cp_parser_trait_expr): Likewise. + * semantics.c (trait_expr_value): Handle the new RID_*. + (finish_trait_expr): Likewise. + +2020-10-24 Marek Polacek <polacek@redhat.com> + + PR c++/96241 + * constexpr.c (cxx_eval_array_reference): Set up ctx->ctor if we + are initializing an aggregate. Call free_constructor on the new + CONSTRUCTOR if it isn't returned from cxx_eval_constant_expression. + +2020-10-23 Marek Polacek <polacek@redhat.com> + + PR c++/91741 + * typeck.c (cp_build_binary_op): Implement -Wsizeof-array-div. + +2020-10-22 Patrick Palka <ppalka@redhat.com> + + PR c++/97328 + * constexpr.c (init_subob_ctx): Don't punt on RANGE_EXPR + indexes, instead build a sub-aggregate initialization context + with no subobject. + +2020-10-22 Patrick Palka <ppalka@redhat.com> + + PR c++/96575 + * constexpr.c (cxx_eval_constant_expression) + <case EMPTY_CLASS_EXPR>: Lower it to a CONSTRUCTOR. + (potential_constant_expression_1) <case COMPOUND_EXPR>: Remove + now-redundant handling of COMPOUND_EXPR with EMPTY_CLASS_EXPR + second operand. + <case EMPTY_CLASS_EXPR>: Return true instead of false. + +2020-10-22 Patrick Palka <ppalka@redhat.com> + + PR c++/97511 + * decl.c (duplicate_decls): Return NULL_TREE if + DECL_TEMPLATE_PARM_P differ. + +2020-10-20 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (push_local_extern_decl_alias): Reconstextualize + alias' parm decls. Drop any default args. + +2020-10-19 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/97438 + * coroutines.cc (struct coroutine_info): Add a field to + record that we emitted a promise type error. + (coro_promise_type_found_p): Check for the case that the + promise type contains both return_void and return_value. + Emit an error if so, with information about the wrong + type methods. + +2020-10-16 Nathan Sidwell <nathan@acm.org> + + PR c++/97460 + * pt.c (push_template_decl): Check DECL_LANG_SPECIFIC in friend + case. + +2020-10-16 Nathan Sidwell <nathan@acm.org> + + PR c++/96258 + * parser.c (cp_parser_declaration): Make token2 point to EOF if + token1 was EOF. + +2020-10-15 Jason Merrill <jason@redhat.com> + + PR c++/95844 + * decl.c (copy_fn_p): Return false for a function that is neither a + constructor nor an assignment operator. + (move_signature_fn_p): Likewise. + +2020-10-15 Marek Polacek <polacek@redhat.com> + + PR c++/97406 + PR c++/85901 + * cxx-pretty-print.c (pp_cxx_type_specifier_seq): Handle OFFSET_TYPE. + (cxx_pretty_printer::abstract_declarator): Fix the printing of ')'. + (cxx_pretty_printer::direct_abstract_declarator): Handle OFFSET_TYPE. + (cxx_pretty_printer::type_id): Likewise. Print the abstract declarator + for pointers-to-members. + +2020-10-14 Jason Merrill <jason@redhat.com> + + PR c++/97358 + * pt.c (check_for_bare_parameter_packs): Diagnose use of + capture pack. + +2020-10-14 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct lang_decl_fn): Adjust context comment. + (DECL_FRIEND_P): Replace with ... + (DECL_UNIQUE_FRIEND_P): ... this. Only for FUNCTION_DECLs. + (DECL_FRIEND_CONTEXT): Adjust. + * class.c (add_implicitly_declared_members): Detect friendly + spaceship from context. + * constraint.cc (remove_constraints): Use a checking assert. + (maybe_substitute_reqs_for): Use DECL_UNIQUE_FRIEND_P. + * decl.c (check_no_redeclaration_friend_default_args): + DECL_UNIQUE_FRIEND_P is signficant, not hiddenness. + (duplicate_decls): Adjust DECL_UNIQUE_FRIEND_P clearing. + (redeclaration_error_message): Use DECL_UNIQUE_FRIEND_P. + (start_preparsed_function): Correct in-class friend processing. + Refactor some initializers. + (grokmethod): Directly check friend decl-spec. + * decl2.c (grokfield): Check DECL_UNIQUE_FRIEND_P. + * friend.c (do_friend): Set DECL_UNIQUE_FRIEND_P first, remove + extraneous conditions. Don't re set it afterwards. + * name-lookup.c (lookup_elaborated_type_1): Simplify revealing + code. + (do_pushtag): Likewise. + * pt.c (optimize_specialization_lookup_p): Check + DECL_UNIQUE_FRIEND_P. + (push_template_decl): Likewise. Drop unneeded friend setting. + (type_dependent_expression_p): Check DECL_UNIQUE_FRIEND_P. + +2020-10-14 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (push_local_extern_decl_alias): Push into alias's + namespace and use pushdecl. + (do_pushdecl_with_scope): Clarify behaviour. + +2020-10-12 Martin Sebor <msebor@redhat.com> + + PR c++/97201 + * error.c (dump_type_suffix): Handle both the C and C++ forms of + zero-length arrays. + +2020-10-12 Martin Sebor <msebor@redhat.com> + + PR c++/96511 + PR middle-end/96384 + * init.c (warn_placement_new_too_small): Call builtin_objsize instead + of duplicating what it does. + +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. + * mangle.c (write_expression): Express unions with a designator. + +2020-07-10 Jason Merrill <jason@redhat.com> + + * pt.c (convert_nontype_argument): Handle REAL_TYPE. + (invalid_nontype_parm_type_p): Allow all structural types. + * tree.c (structural_type_p): Use SCALAR_TYPE_P. + +2020-07-10 Jason Merrill <jason@redhat.com> + + PR c++/96105 + PR c++/96052 + PR c++/95976 + * class.c (check_field_decls): An array of empty classes is not an + empty data member. + (layout_empty_base_or_field): Handle explicit alignment. + Fix union handling. + +2020-07-09 Julian Brown <julian@codesourcery.com> + Thomas Schwinge <thomas@codesourcery.com> + + PR middle-end/95270 + * semantics.c (finish_omp_clauses): Likewise. + +2020-07-09 Patrick Palka <ppalka@redhat.com> + + PR c++/96132 + * constexpr.c (potential_constant_expression_1) <case PARM_DECL>: + Restore dependent_type_p check that guarded the call to + is_really_empty_class. + +2020-07-08 Patrick Palka <ppalka@redhat.com> + + PR c++/95497 + * constexpr.c (potential_constant_expression_1) <case PARM_DECL>: + When processing_template_decl, check COMPLETE_TYPE_P before + calling is_really_empty_class. Don't check dependent_type_p. + +2020-07-08 Marek Polacek <polacek@redhat.com> + + PR c++/96103 + * parser.c (cp_parser_decltype): Print error about using decltype(auto) + in C++11. Check that the token following "auto" is ")". + +2020-07-07 Patrick Palka <ppalka@redhat.com> + + PR c++/95303 + * cxx-pretty-print.c (pp_cxx_unqualified_id): Check + PRIMARY_TEMPLATE_P before printing the innermost template + arguments. + +2020-07-07 Martin Sebor <msebor@redhat.com> + + PR c++/96063 + * parser.c (class_decl_loc_t::diag_mismatched_tags): Print notes only + if warning_at returns nonzero. + +2020-07-06 Martin Sebor <msebor@redhat.com> + + PR c++/95984 + * call.c (build_over_call): Check calls only when tf_warning is set. + +2020-07-06 Nathan Sidwell <nathan@acm.org> + + * decl.c (push_library_fn): Return the decl pushdecl_toplevel returns. + * except.c (verify_library_fn): Replace with ... + (declare_library_fn_1): ... this fn. Always push the fn. + (declare_library_fn): Call it. + (build_throw): Call declare_library_fn_1. + +2020-07-06 Jonathan Wakely <jwakely@redhat.com> + + PR c++/96068 + * parser.c (cp_parser_toplevel_declaration): Only do pedwarn for + empty-declaration in C++98. + +2020-07-02 Jason Merrill <jason@redhat.com> + Jakub Jelinek <jakub@redhat.com> + + * decl.c (grokfndecl): Allow consteval virtual. + * search.c (check_final_overrider): Check consteval mismatch. + * constexpr.c (cxx_eval_thunk_call): New. + (cxx_eval_call_expression): Call it. + * cvt.c (cp_get_fndecl_from_callee): Handle FDESC_EXPR. + * decl2.c (mark_vtable_entries): Track vtables with consteval. + (maybe_emit_vtables): Pass consteval_vtables through. + (clear_consteval_vfns): Replace consteval with nullptr. + (c_parse_final_cleanups): Call it. + +2020-07-01 Nathan Sidwell <nathan@acm.org> + + * class.c (copy_fndecl_with_name): Add additional predicate args, do + not deduce them locally. + (copy_operator_fn): Adjust copy_fndecl_with_name call. + (build_clone): Add vtt and inherited predicate args. Pass through + to copy_fndecl_with_name call. + (build_cdtor_clones): Likewise, pass through to build_clone as + needed. + (build_cdtor): Determine vtt and inherited here. + * cp-tree.h (DECL_NEEDS_CTT_PARM_P): Delete. + +2020-06-30 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (copy_fndecl_with_name): Rename to ... + (copy_operatorn_fn): ... this. Change arg type. + (clone_function_decl): Rename to ... + (clone_cdtor): ... this. + * class.c (copy_fndecl_with_name): Make static. + (copy_operator_fn): New wrapper. + (build_clones): Rename to ... + (build_cdtor_clones): ... this. + (clone_function_decl): Rename to ... + (clone_cdtor): ... this. Adjust build_clones calls. + (clone_constructors_and_destructors): Adjust clone_function_decl + calls. + * method.c (implicitly_declare_fn): Adjust copy_fndecl_with_name + call. + (lazily_declare_fn): Adjust clone_function_decl call. + * pt.c (tsubst_function_decl): Likewise. + (instantiate_template_1): Likewise. + +2020-06-30 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Remove trailing + space in a diagnostic. + +2020-06-30 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (expand_one_await_expression): Remove + code dealing with initial suspend. + (build_actor_fn): Remove code special-casing initial + and final suspend. Handle the final suspend and marking + of the coroutine as done. + (coro_rewrite_function_body): New. + (bind_expr_find_in_subtree): Remove. + (coro_body_contains_bind_expr_p): Remove. + (morph_fn_to_coro): Split the rewrite of the original + function into coro_rewrite_function_body and call it. + +2020-06-29 Marek Polacek <polacek@redhat.com> + + PR c++/94553 + * decl.c (duplicate_decls): Make sure a concept or a variable + template is unique in its declarative region. + +2020-06-29 Marek Polacek <polacek@redhat.com> + + PR c++/95568 + * pt.c (collect_ctor_idx_types): Use TREE_TYPE. + +2020-06-28 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95711 + * coroutines.cc (register_local_var_uses): Skip past + namespace decls. + +2020-06-27 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95736 + * coroutines.cc (get_awaitable_var): New helper. + (build_co_await): Check more carefully before + copying an awaitable. + (expand_one_await_expression): No initializer + is required when the awaitable is not a temp. + (register_awaits): Remove handling that is now + completed when the await expression is built. + +2020-06-27 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Diagnose unavailable + get_return_object_on_allocation_failure. + +2020-06-26 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95519 + * coroutines.cc (struct coroutine_info):Add a field + to hold computed p.return_void expressions. + (coro_build_promise_expression): New. + (get_coroutine_return_void_expr): New. + (finish_co_yield_expr): Build the promise expression + using coro_build_promise_expression. + (finish_co_return_stmt): Likewise. + (build_init_or_final_await): Likewise. + (morph_fn_to_coro): Likewise, for several cases. + +2020-06-26 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Handle error + returns in building g-r-o-o-a-f expressions. + +2020-06-24 Nicholas Krause <xerofoify@gmail.com> + + PR c++/95672 + * typeck2.c (cxx_incomplete_type_diagnostic): Add missing + TYPE_EXPANSION_PACK check for diagnosing incomplete types in + cxx_incomplete_type_diagnostic. + +2020-06-24 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95518 + PR c++/95813 + * coroutines.cc (act_des_fn): Copy function + attributes onto the outlined coroutine helpers. + +2020-06-24 Jason Merrill <jason@redhat.com> + + * call.c (build_over_call): Only call build_base_path once. + +2020-06-24 Jason Merrill <jason@redhat.com> + + PR c++/95719 + * call.c (build_over_call): Look up the overrider in base_binfo. + * class.c (lookup_vfn_in_binfo): Look through BINFO_PRIMARY_P. + +2020-06-23 Jason Merrill <jason@redhat.com> + + PR c++/93976 + Implement C++20 P2082R1, Fixing CTAD for aggregates. + * cp-tree.h (TPARMS_PRIMARY_TEMPLATE): Split out from... + (DECL_PRIMARY_TEMPLATE): ...here. + (builtin_guide_p): Declare. + * decl.c (reshape_init_class): Handle bases of a template. + (reshape_init_r): An array with dependent bound takes a single + initializer. + * pt.c (tsubst_default_argument): Shortcut {}. + (unify_pack_expansion): Allow omitted arguments to trailing pack. + (builtin_guide_p): New. + (collect_ctor_idx_types): Give a trailing pack a {} default + argument. Handle arrays better. + +2020-06-23 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95477 + * coroutines.cc (morph_fn_to_coro): Apply a cleanup to + the get return object when the DTOR is non-trivial. + +2020-06-20 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95505 + * coroutines.cc (morph_fn_to_coro): Update handling of + get-return-object-on-allocation-fail and diagnose missing + std::nothrow. + +2020-06-20 Jason Merrill <jason@redhat.com> + + * call.c (joust): Only compare constraints for non-template + candidates with matching parameters. + * pt.c (tsubst_pack_expansion): Fix getting a type parameter + pack. + (more_specialized_fn): Only compare constraints for candidates with + matching parameters. + +2020-06-19 Jason Merrill <jason@redhat.com> + + * method.c (early_check_defaulted_comparison): Allow defaulting + comparison outside class. Complain if non-member operator isn't a + friend. + +2020-06-18 Jason Merrill <jason@redhat.com> + + * method.c (early_check_defaulted_comparison): Check for &&. + (build_comparison_op): Allow empty union. Diagnose non-category + type. + (common_comparison_type): Remove handling for non-category type. + +2020-06-18 Marek Polacek <polacek@redhat.com> + + PR c++/95735 + * pt.c (finish_template_variable): Return if + coerce_innermost_template_parms return error_mark_node. + +2020-06-18 Marek Polacek <polacek@redhat.com> + + PR c++/95728 + * pt.c (tsubst_copy_and_build) <case NEW_EXPR>: Return error_mark_node + if placement is erroneous. + +2020-06-17 Jonathan Wakely <jwakely@redhat.com> + + PR c++/66159 + * parser.c (cp_parser_elaborated_type_specifier): Do not warn + unless in a declaration. + +2020-06-17 Jason Merrill <jason@redhat.com> + + * cp-tree.h (copy_fndecl_with_name): Declare. + * class.c (copy_fndecl_with_name): Split out from... + (build_clone): ...here. + (add_implicitly_declared_members): Add op== to TYPE_FIELDS. + * method.c (implicitly_declare_fn): Use copy_fndecl_with_name. + +2020-06-17 Jason Merrill <jason@redhat.com> + + * call.c (build_new_op_1): Don't look for a CALL_EXPR when + calling a consteval function. + +2020-06-17 Jason Merrill <jason@redhat.com> + + * decl2.c (grokfield): Pass SD_DEFAULTED and SD_DELETED. + * decl.c (duplicate_decls): Reduce error for delete + after earlier declaration to pedwarn. + +2020-06-17 Marek Polacek <polacek@redhat.com> + + PR c++/95508 + * constexpr.c (maybe_fold_non_dependent_expr): New. + * cp-tree.h (maybe_fold_non_dependent_expr): Declare. + * typeck.c (cp_build_array_ref): Call maybe_fold_non_dependent_expr + instead of maybe_constant_value. + +2020-06-16 Marek Polacek <polacek@redhat.com> + + PR c++/95369 + * call.c (add_list_candidates): Return if a designated initializer + is used with a non-aggregate. + (implicit_conversion_error): Give an error for the case above. + +2020-06-16 Marek Polacek <polacek@redhat.com> + + PR c++/95560 + * name-lookup.c (check_local_shadow): Check if types are + non-null before calling same_type_p. + +2020-06-16 Jakub Jelinek <jakub@redhat.com> + + * semantics.c (handle_omp_for_class_iterator): Adjust + c_omp_check_loop_iv_exprs caller. + (finish_omp_for): Likewise. Don't call fold_build_cleanup_point_expr + before calling c_finish_omp_for and c_omp_check_loop_iv, move it + after those calls. + * pt.c (tsubst_omp_for_iterator): Handle non-rectangular loops. + +2020-06-16 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_schedule): Reject modifier separated + from kind by comma rather than colon. + +2020-06-16 Patrick Palka <ppalka@redhat.com> + + * pt.c (perform_instantiation_time_access_checks): No need to + tsubst into decl. + * semantics.c (enforce_access): Verify that decl is not + dependent. + +2020-06-16 Patrick Palka <ppalka@redhat.com> + + PR c++/41437 + PR c++/47346 + * cp-tree.h (qualified_typedef_usage_s): Delete. + (qualified_typedef_usage_t): Delete. + (deferred_access_check): Move up in file. + (tree_template_info::typedefs_needing_access_checking): Delete. + (tree_template_info::deferred_access_checks): New field. + (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): Rename to ... + (TI_DEFERRED_ACCESS_CHECKS): ... this, and adjust accordingly. + * pt.c (perform_typedefs_access_check): Rename to ... + (perform_instantiation_time_access_checks): ... this, and adjust + accordingly. Remove unnecessary tree tests. + (instantiate_class_template_1): Adjust accordingly. + (instantiate_decl): Likewise. + * semantics.c (enforce_access): Likewise. + +2020-06-16 Patrick Palka <ppalka@redhat.com> + + PR c++/41437 + PR c++/47346 + * call.c (enforce_access): Move to semantics.c. + * cp-tree.h (enforce_access): Delete. + (get_types_needing_access_check): Delete. + (add_typedef_to_current_template_for_access_check): Delete. + * decl.c (make_typename_type): Adjust accordingly. Use + check_accessibility_of_qualified_id instead of directly using + perform_or_defer_access_check. + * parser.c (cp_parser_template_declaration_after_parameters): + Don't push a dk_no_check access state when parsing a template. + * pt.c (get_types_needing_access_check): Delete. + (append_type_to_template_for_access_check_1): Delete. + (perform_typedefs_access_check): Adjust. If type_decl is a + FIELD_DECL, also check its DECL_CONTEXT for dependence. Use + tsubst_copy instead of tsubst to substitute into type_decl so + that we substitute into the DECL_CONTEXT of a FIELD_DECL. + (append_type_to_template_for_access_check): Delete. + * search.c (accessible_p): Remove the processing_template_decl + early exit. + * semantics.c (enforce_access): Moved from call.c. If we're + parsing a template and the access check failed, add the check to + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING. + (perform_or_defer_access_check): Adjust comment. + (add_typedef_to_current_template_for_access_check): Delete. + (check_accessibility_of_qualified_id): Adjust accordingly. + Exit early if the scope is dependent. + +2020-06-11 Patrick Palka <ppalka@redhat.com> + + PR c++/93467 + * constraint.cc (associate_classtype_constraints): If there is a + discrepancy between the current template depth and the template + depth of the original declaration, then adjust the template + parameter depth within the current constraints appropriately. + * pt.c (tsubst_friend_class): Substitute into and set the + constraints on the injected declaration. + +2020-06-11 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (instantiate_coro_traits): Pass a reference + to lambda closure objects to traits instantiation. + (morph_fn_to_coro): Likewise for promise parameter + preview and allocator lookup. + +2020-06-10 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95440 + * call.c (add_candidates): Use vec_safe_length() for + testing the arguments list. + (build_new_method_call_1): Use vec_safe_is_empty() when + checking for an empty args list. + +2020-06-10 Marek Polacek <polacek@redhat.com> + + PR c++/95562 + * parser.c (cp_parser_direct_declarator): Clear + CP_PARSER_FLAGS_DELAY_NOEXCEPT if the declarator kind is not + cdk_id. + +2020-06-09 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95137 + * coroutines.cc (expand_one_await_expression): Build separate + DTOR trees for the awaitable object on the destroy and resume + paths. + +2020-06-09 Jason Merrill <jason@redhat.com> + + PR c++/95552 + * cp-gimplify.c (predeclare_vla): Only predeclare a VLA if it's + wrapped in a pointer type. + +2020-06-05 Marek Polacek <polacek@redhat.com> + + PR c++/95369 + * call.c (build_converted_constant_expr_internal): Allow + list-initialization. + +2020-06-05 Iain Sandoe <iain@sandoe.co.uk> + + * cp-tree.def (CO_RETURN_EXPR): Correct the class + to use tcc_statement. + +2020-06-05 Jason Merrill <jason@redhat.com> + + * error.c (dump_binary_op): Handle negative operand to + POINTER_PLUS_EXPR. + +2020-06-04 Jason Merrill <jason@redhat.com> + + PR c++/93310 + * constexpr.c (cxx_eval_constant_expression) [OBJ_TYPE_REF]: + Evaluate OBJ_TYPE_REF_EXPR. + +2020-06-04 Jason Merrill <jason@redhat.com> + + PR c++/95158 + * class.c (lookup_vfn_in_binfo): New. + * call.c (build_over_call): Use it. + * cp-tree.h (resolves_to_fixed_type_p): Add default argument. + (lookup_vfn_in_binfo): Declare. + +2020-06-04 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95346 + * coroutines.cc (morph_fn_to_coro): Ensure that the get- + return-object is constructed correctly; When it is not the + final return value, pass it to the CTOR of the return type + as an rvalue, per the standard comment. + +2020-06-04 Jakub Jelinek <jakub@redhat.com> + + PR c++/82304 + PR c++/95307 + * constexpr.c (cxx_eval_constant_expression): Diagnose CONVERT_EXPR + conversions from pointer types to arithmetic types here... + (cxx_eval_outermost_constant_expr): ... instead of here. + +2020-06-03 Mark Wielaard <mark@klomp.org> + + * parser.c (cp_lexer_safe_previous_token): New function. + (cp_parser_error_1): Add name_hint if the previous token is + a string literal and next token is a CPP_NAME and we have a + missing header suggestion for the name. + +2020-06-03 Patrick Palka <ppalka@redhat.com> + + * pt.c (process_partial_specialization): Pass the full set of + generic template arguments to strictly_subsumes. + +2020-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/92103 + * pt.c (most_specialized_partial_spec): Reorganize the loop over + DECL_TEMPLATE_SPECIALIZATIONS. Check constraints_satisfied_p on + the original template declaration, not on the tsubsted one. + +2020-06-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95345 + * coroutines.cc (finish_co_await_expr): Revise to allow for + parameter packs. + (finish_co_yield_expr): Likewise. + +2020-06-03 Jason Merrill <jason@redhat.com> + + PR c++/95232 + * cp-tree.h (predeclare_vla): Declare. + * cp-gimplify.c (predeclare_vla): Handle getting a decl. + * pt.c (tsubst_expr) [DECL_EXPR]: Use it. + +2020-06-03 Tobias Burnus <tobias@codesourcery.com> + + * cp-gimplify.c (cxx_omp_predetermined_mapping): New. + * cp-objcp-common.h (LANG_HOOKS_OMP_PREDETERMINED_MAPPING): Redfine. + * cp-tree.h (cxx_omp_predetermined_mapping): Declare. + +2020-06-02 Jason Merrill <jason@redhat.com> + + PR c++/95193 + * pt.c (tsubst_decl): Relax assert. + +2020-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95050 + * coroutines.cc (build_co_await): Wrap the co_await expression + in a TARGET_EXPR, where needed. + (finish_co_yield_expr): Likewise. + +2020-06-02 Patrick Palka <ppalka@redhat.com> + + PR c++/92633 + PR c++/92838 + * pt.c (tsubst_function_decl): Don't do set_constraints when + regenerating a lambda. + (tsubst_lambda_expr): Substitute into the lambda's constraints + and do set_constraints here. + +2020-06-01 Jason Merrill <jason@redhat.com> + + PR c++/95466 + PR c++/95311 + PR c++/95221 + * class.c (build_vfn_ref): Revert 95311 change. + * cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): Build a + COMPOUND_EXPR. + +2020-06-01 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95350 + * coroutines.cc (struct param_info): Remove rv_ref field. + (build_actor_fn): Remove specifial rvalue ref handling. + (morph_fn_to_coro): Likewise. + +2020-05-31 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95087 + * coroutines.cc (morph_fn_to_coro): If we see an + early fatal error, drop the erroneous function body. + +2020-05-31 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_co_await): Remove unused + variable. + (finish_co_await_expr): Likewise. + (finish_co_yield_expr): Likewise; revise comment. + +2020-05-30 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Revise initialization + of the frame pointer to avoid an unused value. + +2020-05-30 Patrick Palka <ppalka@redhat.com> + + PR c++/95386 + * constraint.cc (satisfaction_value): Accept INTEGER_CST of any + boolean type. + +2020-05-29 Patrick Palka <ppalka@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/95181 + * class.c (add_method): Let special member function templates + coexist if they are not equivalently constrained, or in a class + template. + +2020-05-29 Jason Merrill <jason@redhat.com> + + PR c++/95371 + * pt.c (process_template_parm): Set DECL_TEMPLATE_INFO + on the DECL_TEMPLATE_RESULT. + +2020-05-29 Marek Polacek <polacek@redhat.com> + + PR c++/95344 + * cp-gimplify.c (cp_fold) <case MODIFY_EXPR>: Don't set + TREE_THIS_VOLATILE here. + (cp_fold): Set it here along with TREE_NO_WARNING. + +2020-05-29 Jason Merrill <jason@redhat.com> + + PR c++/95311 + PR c++/95221 + * class.c (build_vfn_ref): Don't fold the INDIRECT_REF. + +2020-05-29 Patrick Palka <ppalka@redhat.com> + + PR c++/92652 + PR c++/93698 + PR c++/94128 + * parser.c (cp_parser_requires_clause_expression): Temporarily + increment processing_template_decl only if it is 0. + (cp_parser_constraint_expression): Likewise. + (cp_parser_requires_expression): Likewise. + +2020-05-29 Patrick Palka <ppalka@redhat.com> + + PR c++/95241 + * constexpr.c (get_or_insert_ctor_field): Add limited support + for RANGE_EXPR index lookups. + +2020-05-28 Jakub Jelinek <jakub@redhat.com> + + PR c++/95328 + * decl.c (cp_finish_decomp): Call complete_type before checking + COMPLETE_TYPE_P. + +2020-05-28 Jason Merrill <jason@redhat.com> + + PR c++/94926 + * decl.c (cp_finish_decl): Revert r9-297 change. + (check_static_variable_definition): Likewise. + * constexpr.c (ensure_literal_type_for_constexpr_object): Likewise. + * pt.c (instantiate_decl): Return early on type error. + +2020-05-27 Jason Merrill <jason@redhat.com> + + PR c++/95319 + * decl.c (reshape_init_array_1): Don't reuse in overload context. + +2020-05-27 Jason Merrill <jason@redhat.com> + + PR c++/95242 + * call.c (build_new_op_1): Suppress + warn_zero_as_null_pointer_constant across comparison of <=> result + to 0. + +2020-05-27 Jason Merrill <jason@redhat.com> + + PR c++/95222 + * decl.c (grokdeclarator): Don't shift attributes in TYPENAME + context. + +2020-05-27 Nathan Sidwell <nathan@acm.org> + + PR c++/95263 + * pt.c (lookup_template_class_1): Restore alias template mutation. + +2020-05-26 Jakub Jelinek <jakub@redhat.com> + + PR c++/95197 + * cp-gimplify.c: Include omp-general.h. + (cp_genericize_r) <case OMP_DISTRIBUTE>: For class iteration + variables in composite distribute parallel for, instantiate copy + ctor of their types. + +2020-05-23 Patrick Palka <ppalka@redhat.com> + + PR c++/94038 + * constexpr.c (cxx_eval_constant_expression) + <case TEMPLATE_ID_EXPR>: Don't evaluate the concept when + constexpr evaluation is uid-sensitive. + +2020-05-22 Jason Merrill <jason@redhat.com> + + * cp-gimplify.c (cp_gimplify_expr) [CALL_EXPR]: Don't preevaluate + the function address if the call used operator syntax. + +2020-05-21 Jason Merrill <jason@redhat.com> + + PR c++/95221 + * cp-ubsan.c (cp_ubsan_maybe_instrument_member_call): For a virtual + call, instrument the OBJ_TYPE_REF. + + * decl.c (compute_array_index_type_loc): Diagnose expressions + in a template that can't be constant. + * parser.c (cp_parser_direct_declarator): Don't check + non-constant array bounds here. + + * cp-tree.h (is_rvalue_constant_expression): Declare. + * constexpr.c (is_rvalue_constant_expression): New. + * parser.c (cp_parser_constant_expression): Use it. + * decl.c (cp_finish_decl): Try to treat a constexpr initializer in a + template as constant. + + * typeck.c (build_x_modify_expr): Handle error_mark_node arguments. + + * decl.c (grokparms): Return NULL_TREE if any parms were erroneous. + +2020-05-21 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (finish_co_return_stmt): Revert change to use + finish_expr_stmt. + +2020-05-21 Patrick Palka <ppalka@redhat.com> + + PR c++/94038 + * constexpr.c (constexpr_ctx::uid_sensitive): Remove field. + (uid_sensitive_constexpr_evaluation_value): Define. + (uid_sensitive_constexpr_evaluation_true_counter): Define. + (uid_sensitive_constexpr_evaluation_p): Define. + (uid_sensitive_constexpr_evaluation_sentinel): Define its + constructor. + (uid_sensitive_constexpr_evaluation_checker): Define its + constructor and its evaluation_restricted_p method. + (get_fundef_copy): Remove 'ctx' parameter. Use u_s_c_e_p + instead of constexpr_ctx::uid_sensitive. + (cxx_eval_call_expression): Use u_s_c_e_p instead, and test it + last. Adjust call to get_fundef_copy. + (instantiate_cx_fn_r): Test u_s_c_e_p so that we increment the + counter if necessary. + (cxx_eval_outermost_constant_expr): Remove 'uid_sensitive' + parameter. Adjust function body accordingly. + (maybe_constant_value): Remove 'uid_sensitive' parameter and + adjust function body accordingly. Set up a + uid_sensitive_constexpr_evaluation_checker, and use it to + conditionally update the cv_cache. + * cp-gimplify.c (cp_fold): Set up a + uid_sensitive_constexpr_evaluation_checker, and use it to + conditionally update the fold_cache. + * cp-tree.h (maybe_constant_value): Update declaration. + (struct uid_sensitive_constexpr_evaluation_sentinel): Define. + (struct sensitive_constexpr_evaluation_checker): Define. + * expr.c (fold_for_warn): Set up a + uid_sensitive_constexpr_evaluation_sentinel before calling + the folding subroutines. Drop all but the first argument to + maybe_constant_value. + +2020-05-20 Marek Polacek <polacek@redhat.com> + + DR 2237 + * parser.c (cp_parser_unqualified_id): Reject simple-template-id as + the declarator-id of a destructor. + (cp_parser_constructor_declarator_p): Reject simple-template-id as + the declarator-id of a constructor. + +2020-05-20 Marek Polacek <polacek@redhat.com> + + DR 2289 + PR c++/94553 + * cp-tree.h (SD_DECOMPOSITION): New flag. + * decl.c (duplicate_decls): Make sure a structured binding is unique + in its declarative region. + (start_decl): If INITIALIZED is SD_DECOMPOSITION, call + fit_decomposition_lang_decl. + (grokdeclarator): Compare INITIALIZED directly to SD_* flags. + * parser.c (cp_parser_decomposition_declaration): Pass SD_DECOMPOSITION + to start_decl. + +2020-05-20 Patrick Palka <ppalka@redhat.com> + + PR c++/95223 + * typeck.c (structural_comptypes): Don't perform + context-dependent resolution of TYPENAME_TYPEs when + comparing_specializations. + +2020-05-19 Nathan Sidwell <nathan@acm.org> + + * pt.c (lookup_template_class_1): Do not reinit template_info of an + alias here. + +2020-05-18 Martin Sebor <msebor@redhat.com> + + PR c++/94923 + * call.c ((maybe_warn_class_memaccess): Use is_byte_access_type. + * cp-tree.h (is_dummy_object): Return bool. + (is_byte_access_type): Declare new function. + * tree.c (is_dummy_object): Return bool. + (is_byte_access_type): Define new function. + +2020-05-19 Patrick Palka <ppalka@redhat.com> + + PR c++/87847 + * pt.c (init_template_processing): Enable sanitization for + decl_specializations and type_specializations. + + PR c++/66439 + * pt.c (fn_type_unification): Pass 'fn' instead of NULL_TREE as + the 'in_decl' parameter to coerce_template_parms. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + PR c++/94955 + * typeck.c (cp_build_binary_op): Use fold_for_warn instead of + cp_fold_rvalue. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + PR c++/94937 + * cvt.c (cp_get_fndecl_from_callee): Return NULL_TREE if the function + type is not INDIRECT_TYPE_P. + * decl.c (omp_declare_variant_finalize_one): Call + cp_get_callee_fndecl_nofold instead of looking for the function decl + manually. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + PR c++/90915 + * parser.c (cp_parser_has_attribute_expression): Sorry on a + type-dependent argument. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + DR 1512 + PR c++/87699 + * call.c (add_builtin_candidate) <case EQ_EXPR>: Create candidate + operator functions when type is std::nullptr_t for ==/!=. + * typeck.c (composite_pointer_type_r): Add a bool * parameter. Use it + to maybe add "const" to the pointer type. + (composite_pointer_type): Update the call to composite_pointer_type_r. + (cp_build_binary_op): Turn two warning_at into error_at. Print the + types. + +2020-05-18 Jason Merrill <jason@redhat.com> + + * call.c (build_over_call): Remove unnecessary + cp_stabilize_reference. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + * call.c (add_builtin_candidate): Don't create a builtin overload + candidate for ++ when type is bool in C++17. + +2020-05-18 Marek Polacek <polacek@redhat.com> + + * cfns.h: Regenerated. + +2020-05-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Initialize the gro variable. + +2020-05-16 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (finish_co_return_stmt): Implement rules + from [class.copy.elision] /3. + +2020-05-16 Patrick Palka <ppalka@redhat.com> + + PR c++/57943 + * semantics.c (finish_decltype_type): Call + instantiate_non_dependent_expr_sfinae on the expression. + +2020-05-15 Patrick Palka <ppalka@redhat.com> + + Revert: + + 2020-04-07 Patrick Palka <ppalka@redhat.com> + + PR c++/90996 + * typeck2.c (process_init_constructor_array): Propagate + CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to + the array initializer. + +2020-05-15 Jason Merrill <jason@redhat.com> + + PR c++/93286 - ICE with __is_constructible and variadic template. + * pt.c (tsubst_tree_list): New. + (tsubst, tsubst_copy_and_build): Use it. + * decl2.c (is_late_template_attribute): Handle error_mark_node args. + +2020-05-15 Nathan Sidwell <nathan@acm.org> + + * pt.c (template_args_equal): Fix thinkos in previous 'cleanup'. + +2020-05-14 Jason Merrill <jason@redhat.com> + + PR c++/93901 + * pt.c (maybe_instantiate_noexcept): Change clone handling. + +2020-05-14 Patrick Palka <ppalka@redhat.com> + + PR c++/78446 + * call.c (build_op_call): Pass complain to lookup_fnfields. + (build_special_member_call): Likewise. + * class.c (type_requires_array_cookie): Pass tf_warning_or_error + to lookup_fnfields. + * cp-tree.h (lookup_fnfields): Add tsubst_flags_t parameter. + * except.c (build_throw): Pass tf_warning_or_error to + lookup_fnfields. + * init.c (build_new_1): Pass complain to lookup_fnfields. + * method.c (locate_fn_flags): Likewise. + * name-lookup.c (lookup_name_real_1): Pass tf_warning_or_error + to lookup_fnfields. + * pt.c (tsubst_baselink): Pass complain to lookup_fnfields. + * search.c (lookup_fnfields): New 'complain' parameter. Pass it + to lookup_member. + +2020-05-14 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_diagnose_invalid_typename): Mention + std=c++20 not 2a, reformat dependent binfo inform loops. + + * pt.c (tsubst_template_decl): Reorder and commonize some control + paths. + + * pt.c (tsubst_friend_function): Simplify control flow. + + * pt.c (lookup_template_class_1): Remove unnecessary else by + simply grabbing TYPE_NAME earlier. + + * pt.c (push_template_decl_real): Adjust friend pushing logic. + Reinit template type. + + * pt.c (build_template_decl): Init DECL_TEMPLATE_RESULT & + TREE_TYPE here ... + (process_partial_specialization): ... not here ... + (push_template_decl_real, add_inherited_template_parms) + (build_deduction_guide): ... or here. + +2020-05-14 Jakub Jelinek <jakub@redhat.com> + + * cp-gimplify.c (cp_genericize_r): Set cfun->has_omp_target. + +2020-05-13 Patrick Palka <ppalka@redhat.com> + + PR c++/79706 + * init.c (build_vec_delete_1): Just return error_mark_node if + deallocate_expr is error_mark_node. + (build_delete): Just return error_mark_node if do_delete is + error_mark_node. + +2020-05-13 Patrick Palka <ppalka@redhat.com> + + PR c++/95020 + * constraint.cc (tsubst_requires_expr): Produce a new + requires-expression when processing_template_decl, even if + template arguments are not dependent. + +2020-05-13 Marek Polacek <polacek@redhat.com> + + PR c++/95066 + * decl.c (duplicate_decls): Set DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P. + +2020-05-13 Nathan Sidwell <nathan@acm.org> + + * pt.c (template_args_equal): Reorder category checking for + clarity. + + * pt.c (perform_typedefs_access_check): Cache expensively + calculated object references. + (check_auto_in_tmpl_args): Just assert we do not get unexpected + nodes, rather than silently do nothing. + (append_type_to_template_for_access): Likewise, cache expensie + object reference. + + * pt.c (canonical_type_parameter): Simplify. + + Formatting fixups & some simplifications. + * pt.c (spec_hash_table): New typedef. + (decl_specializations, type_specializations): Use it. + (retrieve_specialization): Likewise. + (register_specialization): Remove unnecessary casts. + (push_template_decl_real): Reformat. + (instantiate_class_template_1): Use more RAII. + (make_argument_pack): Simplify. + (instantiate_template_1): Use gcc_checking_assert for expensive + asserts. + (instantiate_decl): Likewise. + (resolve_typename_type): Reformat comment. + * semantics.c (struct deferred_access): Remove unnecessary GTY on + member. + (begin_class_definition): Fix formatting. + +2020-05-13 Jason Merrill <jason@redhat.com> + + * call.c, class.c, constexpr.c, constraint.cc, decl.c, init.c, + lambda.c, lex.c, method.c, name-lookup.c, parser.c, pt.c, tree.c, + typeck2.c: Change cxx2a to cxx20. + +2020-05-12 Marek Polacek <polacek@redhat.com> + + PR c++/95074 + * parser.c (cp_parser_postfix_expression) <case CPP_OPEN_PAREN>: When + looking for a block-scope function declaration, look through the whole + set, not just the first function in the overload set. + +2020-05-12 Jakub Jelinek <jakub@redhat.com> + + PR c++/95063 + * pt.c (tsubst_decl): Deal with DECL_OMP_PRIVATIZED_MEMBER for + a bit-field. + +2020-05-11 Jason Merrill <jason@redhat.com> + + Resolve C++20 NB comment CA104 + * pt.c (determine_specialization): Compare constraints for + specialization of member template of class instantiation. + +2020-05-11 Jason Merrill <jason@redhat.com> + + PR c++/92583 + PR c++/92654 + * tree.c (cp_walk_subtrees): Stop at typedefs. + Handle TYPENAME_TYPE here. + * pt.c (find_parameter_packs_r): Not here. + (for_each_template_parm_r): Clear *walk_subtrees. + * decl2.c (min_vis_r): Look through typedefs. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * call.c (implicit_conversion_error): Split out from... + (perform_implicit_conversion_flags): ...here. + (build_converted_constant_expr_internal): Use it. + +2020-05-11 Jason Merrill <jason@redhat.com> + + PR c++/90748 + * parser.c (inject_parm_decls): Set current_class_ptr here. + (cp_parser_direct_declarator): And here. + (cp_parser_late_return_type_opt): Not here. + (cp_parser_noexcept_specification_opt): Nor here. + (cp_parser_exception_specification_opt) + (cp_parser_late_noexcept_specifier): Remove unneeded parameters. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * decl.c (cxx_init_decl_processing): Call declare_weak for + __cxa_pure_virtual. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * pt.c (instantiate_class_template_1): Call tsubst_expr for + STATIC_ASSERT member. + * ptree.c (cxx_print_xnode): Handle STATIC_ASSERT. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * pt.c (find_parameter_packs_r) [LAMBDA_EXPR]: Remove redundant + walking of capture list. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * cp-tree.h (LOOKUP_EXPLICIT_TMPL_ARGS): Remove. + * call.c (build_new_function_call): Don't set it. + (build_new_method_call_1): Likewise. + (build_over_call): Check cand->explicit_targs instead. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * decl.c (compute_array_index_type_loc): Stabilize before building + the MINUS_EXPR. + +2020-05-11 Jason Merrill <jason@redhat.com> + + * decl.c (grokdeclarator): Adjust deprecated_state here. + (start_decl): Not here. + +2020-05-08 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95003 + * coroutines.cc (build_actor_fn): Ensure that bind scopes + are marked as having side-effects where necessary. + (replace_statement_captures): Likewise. + (morph_fn_to_coro): Likewise. + +2020-05-08 Nathan Sidwell <nathan@acm.org> + + * NEWS: Delete, it is so stale. + + * parser.c (cp_lexer_set_source_position_from_token): EOF has a + location too. + +2020-05-07 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94817 + PR c++/94829 + * coroutines.cc (morph_fn_to_coro): Set unformed outline + functions to error_mark_node. For early error returns suppress + warnings about missing ramp return values. Fix reinstatement + of the function body on pre-existing initial error. + * decl.c (finish_function): Use the normal error path for fails + in the ramp function, do not try to compile the helpers if the + transform fails. + +2020-05-07 Marek Polacek <polacek@redhat.com> + + PR c++/94590 - Detect long double -> double narrowing. + * typeck2.c (check_narrowing): Detect long double -> double + narrowing even when double and long double have the same + precision. Make it handle conversions to float too. + +2020-05-07 Marek Polacek <polacek@redhat.com> + + PR c++/94255 + * parser.c (cp_parser_class_specifier_1): Check that the scope is + nested inside current scope before pushing it. + +2020-05-07 Marek Polacek <polacek@redhat.com> + + P1957R2 + * typeck2.c (check_narrowing): Consider T* to bool narrowing + in C++11 and up. + +2020-05-07 Marek Polacek <polacek@redhat.com> + + * decl.c (grok_op_properties): Fix spelling of non-static. + * typeck.c (build_class_member_access_expr): Likewise. + +2020-05-07 Richard Biener <rguenther@suse.de> + + PR middle-end/94703 + * optimize.c (update_cloned_parm): Copy DECL_NOT_GIMPLE_REG_P. + +2020-05-06 Marek Polacek <polacek@redhat.com> + + PR c++/94938 + * pt.c (tsubst_copy_and_build): Call type_dependent_expression_p_push + instead of uses_template_parms. Move the warning_sentinels after the + RECURs. + +2020-05-06 Jakub Jelinek <jakub@redhat.com> + + PR c++/94951 + * typeck.c (cp_strict_aliasing_warning): New function. + (cp_build_indirect_ref_1, build_reinterpret_cast_1): Use + it instead of strict_aliasing_warning. + + PR c++/94907 + * method.c (defaulted_late_check): Don't call synthesize_method + on constexpr sfk_comparison if it has been called on it already. + +2020-05-06 Nathan Sidwell <nathan@acm.org> + + PR c++/94946 + * decl.c (grokdeclarator): Don't splice template attributes in + parm context -- they can apply to the parm. + +2020-05-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc: Remove references to n4849 throughout. + +2020-05-05 Jason Merrill <jason@redhat.com> + + CWG 2235 + * pt.c (more_specialized_fn): Do consider parms with no deducible + template parameters. + +2020-05-05 Jason Merrill <jason@redhat.com> + + PR c++/90212 + * constexpr.c (potential_constant_expression_1): In a lambda + function, consider a captured variable directly. + +2020-05-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (transform_await_wrapper): Check that we have + no unlowered co_yields. + (captures_temporary): Likewise. + (register_awaits): Likewise. + +2020-05-05 Nathan Sidwell <nathan@acm.org> + + PR c++/94807 + * coroutines.cc (morph_fn_to_coro): Just check for + closure_identifier. + * pt.c (tsubst_function_decl): Update lambda fn's this_ptr name. + +2020-05-05 Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/94799 + * parser.c (cp_parser_postfix_dot_deref_expression): If we have + a type-dependent object of class type, stash it to + parser->context->object_type. If the postfix expression doesn't have + a type, use typeof. + (cp_parser_class_name): Consider object scope too. + (cp_parser_lookup_name): Remove code dealing with the case when + object_type is unknown_type_node. + +2020-05-04 Patrick Palka <ppalka@redhat.com> + + PR c++/94038 + * cp-gimplify.c (cp_fold) <case CALL_EXPR>: Move some variable + declarations closer to their uses. Copy the CALL_EXPR only + when one of its arguments has changed. + <case TREE_VEC>: Instead of first collecting the folded + arguments into a releasing_vec, just make a copy of the TREE_VEC + as soon as folding changes one of its arguments. + +2020-05-04 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (morph_fn_to_coro): Mark the coro.gro variable + as artificial and ignored. + +2020-05-04 Nathan Sidwell <nathan@acm.org> + + pt.c (process_template_parm): Don't walk the template list twice, + remember the final node instead. + (end_template_parm_list): Refactor. Comment on why we do a pop + and a push. + + PR c++/94827 -- don't save parms in nested requirement + * constraint.cc (tsubst_nested_requirement): TYPE directly holds + notmalized requirement. + (finish_nested_requirement): Don't stash current tpl parms into + the requirement. + (diagnose_nested_requirement): TYPE directly holds notmalized + requirement. + +2020-05-01 Patrick Palka <ppalka@redhat.com> + + PR c++/90880 + * cp-tree.h (check_accessibility_of_qualified_id): Add + tsubst_flags_t parameter and change return type to bool. + * parser.c (cp_parser_lookup_name): Pass tf_warning_to_error to + check_accessibility_of_qualified_id. + * pt.c (tsubst_qualified_id): Return error_mark_node if + check_accessibility_of_qualified_id returns false. + * semantics.c (check_accessibility_of_qualified_id): Add + complain parameter. Pass complain instead of + tf_warning_or_error to perform_or_defer_access_check. Return + true unless perform_or_defer_access_check returns false. + +2020-05-01 Marek Polacek <polacek@redhat.com> + + PR c++/94885 + * typeck2.c (process_init_constructor_record): Return PICFLAG_ERRONEOUS + if an initializer element was erroneous. + +2020-05-01 Jason Merrill <jason@redhat.com> + + PR c++/90479 + * init.c (get_nsdmi): Don't push_to_top_level for a local class. + +2020-05-01 Jason Merrill <jason@redhat.com> + + PR c++/91529 + * decl.c (cp_finish_decl): Also clear TREE_READONLY if + -fmerge-all-constants. + +2020-05-01 Jason Merrill <jason@redhat.com> + + PR c++/93822 + * pt.c (tsubst_decl): Make sure DECL_VALUE_EXPR continues to have + the same type as the variable. + +2020-04-30 Jason Merrill <jason@redhat.com> + Nathan Sidwell <nathan@acm.org> + + PR c++/94827 + * constraint.cc (map_arguments): If ARGS is null, it's a + self-mapping of parms. + (finish_nested_requirement): Do not pass argified + current_template_parms to normalization. + (tsubst_nested_requirement): Don't assert no template parms. + +2020-04-30 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94886 + * coroutines.cc (transform_local_var_uses): Defer walking + the DECL_INITIALs of BIND_EXPR vars until all the frame + allocations have been made. + +2020-04-30 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94883 + * coroutines.cc (register_awaits): Update target + expressions for awaitable and suspend handle + initializers. + +2020-04-30 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94879 + * coroutines.cc (build_co_await): Account for variables + with DECL_VALUE_EXPRs. + (captures_temporary): Likewise. + (register_awaits): Likewise. + +2020-04-29 Patrick Palka <ppalka@redhat.com> + + PR c++/94830 + * pt.c (find_template_parameter_info::parm_list): New field. + (keep_template_parm): Use the new field to build up the + parameter list here instead of ... + (find_template_parameters): ... here. Return ftpi.parm_list. + +2020-04-29 Jakub Jelinek <jakub@redhat.com> + + PR target/94707 + * class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty + base artificial FIELD_DECLs. + (layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class + field_poverlapping_p FIELD_DECLs. + +2020-04-29 Patrick Palka <ppalka@redhat.com> + + PR c++/94819 + * constraint.cc (satisfy_declaration_constraints): Use saved_t + instead of t as the key to decl_satisfied_cache. + + PR c++/94808 + * error.c (print_requires_expression_info): Print the dependent + form of the parameter list with its template parameter mapping, + rather than printing the substituted form. + +2020-04-28 Jason Merrill <jason@redhat.com> + + PR c++/94583 + * decl.c (use_eh_spec_block): Check nothrow type after + DECL_DEFAULTED_FN. + * pt.c (maybe_instantiate_noexcept): Call synthesize_method for + DECL_MAYBE_DELETED fns here. + * decl2.c (mark_used): Not here. + * method.c (get_defaulted_eh_spec): Reject DECL_MAYBE_DELETED here. + +2020-04-28 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94760 + * coroutines.cc (instantiate_coro_traits): Pass a reference to + object type rather than a pointer type for 'this', for method + coroutines. + (struct param_info): Add a field to hold that the parm is a lambda + closure pointer. + (morph_fn_to_coro): Check for lambda closure pointers in the + args. Use a reference to *this when building the args list for the + promise allocator lookup. + +2020-04-28 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94759 + * coroutines.cc (coro_promise_type_found_p): Do not + exclude non-classes here (this needs to be handled in the + coroutine header). + (morph_fn_to_coro): Allow for the case where the coroutine + returns void. + +2020-04-27 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94701 + * coroutines.cc (struct local_var_info): Add fields for static + variables and those with DECL_VALUE_EXPR redirection. + (transform_local_var_uses): Skip past typedefs and static vars + and then account for redirected variables. + (register_local_var_uses): Likewise. + +2020-04-27 Jason Merrill <jason@redhat.com> + + PR c++/90750 + PR c++/79585 + * decl.c (grokdeclarator): Move dependent attribute to decl. + * decl2.c (splice_template_attributes): No longer static. + +2020-04-27 Patrick Palka <ppalka@redhat.com> + + PR c++/94772 + * constexpr.c (cxx_eval_call_expression): Don't set new_obj if we're + evaluating the target constructor of a delegating constructor. + (cxx_eval_store_expression): Don't set TREE_READONLY if the LHS of the + INIT_EXPR is '*this'. + +2020-04-26 Marek Polacek <polacek@redhat.com> + + PR c++/90320 + * call.c (struct conversion): Add copy_init_p. + (standard_conversion): Set copy_init_p in ck_base and ck_rvalue + if FLAGS demands LOOKUP_ONLYCONVERTING. + (convert_like_real) <case ck_base>: If copy_init_p is set, or + LOOKUP_ONLYCONVERTING into FLAGS. + +2020-04-26 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94752 + * coroutines.cc (morph_fn_to_coro): Ensure that + unnamed function params have a usable and distinct + frame field name. + +2020-04-24 Jason Merrill <jason@redhat.com> + + PR c++/94583 + * decl.c (redeclaration_error_message): Reject defaulted comparison + operator that has been previously declared. + +2020-04-25 Patrick Palka <ppalka@redhat.com> + + * parser.c (cp_parser_diagnose_invalid_type_name): Suggest enabling + concepts if the invalid identifier is 'requires'. + +2020-04-25 Jakub Jelinek <jakub@redhat.com> + + PR c++/94742 + * semantics.c (finish_call_expr): When looking if all overloads + are noreturn, use STRIP_TEMPLATE to look through TEMPLATE_DECLs. + +2020-04-24 Martin Liska <mliska@suse.cz> + + * coroutines.cc: Fix compilation error for release checking + where we miss declaration of ‘coro_body_contains_bind_expr_p’. + +2020-04-23 Patrick Palka <ppalka@redhat.com> + + * tree.c (zero_init_expr_p): Use uses_template_parms instead of + dependent_type_p. + + PR c++/94645 + * pt.c (template_class_depth): Walk into the DECL_FRIEND_CONTEXT of a + friend declaration rather than into its CP_DECL_CONTEXT. + +2020-04-23 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94288 + * coroutines.cc (await_statement_expander): Simplify cases. + (struct susp_frame_data): Add fields for truth and/or if + cases, rename one field. + (analyze_expression_awaits): New. + (expand_one_truth_if): New. + (add_var_to_bind): New helper. + (coro_build_add_if_not_cond_break): New helper. + (await_statement_walker): Handle conditional expressions, + handle expansion of truth-and/or-if cases. + (bind_expr_find_in_subtree): New, checking-only. + (coro_body_contains_bind_expr_p): New, checking-only. + (morph_fn_to_coro): Ensure that we have a top level bind + expression. + +2020-04-22 Jonathan Wakely <jwakely@redhat.com> + + PR translation/94698 + * class.c (check_field_decls): Change "define" to "declare" in + -Weffc++ diagnostics. + +2020-04-22 Patrick Palka <ppalka@redhat.com> + + PR c++/94719 + PR c++/94549 + * constraint.cc (satisfy_declaration_constraints): If the inherited + constructor points to an instantiation of a constructor template, + remember and use its attached template arguments. + +2020-04-22 Jonathan Wakely <jwakely@redhat.com> + + PR translation/94698 + * class.c (check_field_decls): Change "override" to "define" in + -Weffc++ diagnostics. + +2020-04-22 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94682 + * coroutines.cc (struct param_info): Add a field to note that + the param is 'this'. + (morph_fn_to_coro): Convert this to a reference before using it + in the promise parameter preview. + +2020-04-22 Jason Merrill <jason@redhat.com> + + PR c++/94546 + * pt.c (register_parameter_specializations): If the instantiation is + still a parameter pack, don't wrap it in a NONTYPE_ARGUMENT_PACK. + (tsubst_pack_expansion, tsubst_expr): Adjust. + +2020-04-22 Martin Sebor <msebor@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/94510 + * decl.c (reshape_init_array_1): Avoid stripping redundant trailing + zero initializers... + * mangle.c (write_expression): ...and handle them here even for + pointers to members by calling zero_init_expr_p. + * cp-tree.h (zero_init_expr_p): Declare. + * tree.c (zero_init_expr_p): Define. + (type_initializer_zero_p): Remove. + * pt.c (tparm_obj_values): New hash_map. + (get_template_parm_object): Store to it. + (tparm_object_argument): New. + +2020-04-22 Patrick Palka <ppalka@redhat.com> + + PR c++/67825 + * constraint.cc (diagnose_valid_expression): Check convert_to_void here + as well as in tsubst_valid_expression_requirement. + +2020-04-21 Patrick Palka <ppalka@redhat.com> + + PR c++/94549 + * constraint.cc (satisfy_declaration_constraints): Don't strip the + inherited constructor if it already has template information. + + PR c++/94597 + * pt.c (any_template_parm_r) <case IDENTIFIER_NODE>: New case. If this + is a conversion operator, visit its TREE_TYPE. + +2020-04-21 Nathan Sidwell <nathan@acm.org> + + * pt.c (tsubst_copy_and_build) [POINTER_PLUS_EXPR]: Check for + error_mark_node. + +2020-04-21 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94661 + * coroutines.cc (morph_fn_to_coro): Simplify return + value computation. + +2020-04-17 Marek Polacek <polacek@redhat.com> + + PR c++/94592 + * constexpr.c (cxx_eval_outermost_constant_expr): Return when T is + a BRACE_ENCLOSED_INITIALIZER_P. + (is_nondependent_constant_expression): Don't check + BRACE_ENCLOSED_INITIALIZER_P. + (is_nondependent_static_init_expression): Likewise. + +2020-04-20 Patrick Palka <ppalka@redhat.com> + + PR c++/94628 + * cp-tree.h (lss_policy::lss_nop): New enumerator. + * pt.c (local_specialization_stack::local_specialization_stack): Handle + an lss_nop policy. + (local_specialization_stack::~local_specialization_stack): Likewise. + (tsubst_pack_expansion): Use a local_specialization_stack instead of + manually saving and restoring local_specializations. Conditionally + replace local_specializations sooner, before the handling of the + unsubstituted_packs case. + +2020-04-20 Marek Polacek <polacek@redhat.com> + + PR c++/94505 - bogus -Wparentheses warning with fold-expression. + * pt.c (fold_expression): Add warning_sentinel for -Wparentheses + before calling build_x_binary_op. + +2020-04-20 Marek Polacek <polacek@redhat.com> + + * coroutines.cc (captures_temporary): Don't assign the result of + STRIP_NOPS to the same variable. + +2020-04-20 Nathan Sidwell <nathan@acm.org> + + PR c++/94454 - tpl-tpl-parms are not canonicalizable types + * pt.c (canonical_type_parameter): Assert not a tpl-tpl-parm. + (process_template_parm): tpl-tpl-parms are structural. + (rewrite_template_parm): Propagate structuralness. + + PR c++/94454 - Expr pack expansion equality + * tree.c (cp_tree_equal) [TEMPLATE_ID_EXPR, default]: Refactor. + [EXPR_PACK_EXPANSION]: Add. + + PR c++/94454 Template Argument Hashing + * pt.c (iterative_hash_template_arg): Strip nodes as + template_args_equal does. + [ARGUMENT_PACK_SELECT, TREE_VEC, CONSTRUCTOR]: Refactor. + [node_class:TEMPLATE_TEMPLATE_PARM]: Hash by level & index. + [node_class:default]: Refactor. + +2020-04-18 Patrick Palka <ppalka@redhat.com> + + PR c++/94632 + * tree.c (cp_tree_equal) <case PARM_DECL>: Ignore + comparing_specializations if the parameters' contexts are identical. + + PR c++/92187 + * pt.c (splice_late_return_type): Propagate cv-qualifiers and + PLACEHOLDER_TYPE_CONSTRAINTS from the original auto node to the new one. + +2020-04-17 Patrick Palka <ppalka@redhat.com> + + PR c++/94483 + * lambda.c (lambda_capture_field_type): Avoid doing auto deduction if + the explicit initializer has parameter packs. + + PR c++/88754 + * parser.c (cp_parser_check_template_parameters): Before issuing a hard + error, first try simulating an error instead. + +2020-04-17 Jakub Jelinek <jakub@redhat.com> + + PR other/94629 + * call.c (build_conditional_expr_1): Remove redundant assignment to + arg2. + +2020-04-16 Patrick Palka <ppalka@redhat.com> + + PR c++/94475 + * cvt.c (ocp_convert): If the result of scalar_constant_value is + erroneous, ignore it and use the original expression. + +2020-04-16 Jakub Jelinek <jakub@redhat.com> + + PR c++/94571 + * parser.c (cp_parser_simple_declaration): Fix up a pasto in + diagnostics. + +2020-04-15 Jakub Jelinek <jakub@redhat.com> + + PR c/94593 + * parser.c (cp_parser_pragma) <case PRAGMA_OMP_REQUIRES>: Reject + requires directive when not at file or namespace scope. + +2020-04-14 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94359 + * coroutines.cc (build_actor_fn): Check that the target can + support the resume tailcall before mandating it. + +2020-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/85278 + * cxx-pretty-print.c (cxx_pretty_printer:simple_type_specifier) + <case DECLTYPE_TYPE>: Handle DECLTYPE_TYPE here instead of ... + (pp_cxx_type_specifier_seq) <case DECLTYPE_TYPE>: ... here. + (cxx_pretty_printer::direct_abstract_declarator) <case DECLTYPE_TYPE>: + New no-op case. + + PR c++/94034 + * constexpr.c (replace_result_decl_data): New struct. + (replace_result_decl_data_r): New function. + (replace_result_decl): New function. + (cxx_eval_call_expression): Use it. + * tree.c (build_aggr_init_expr): Set the location of the AGGR_INIT_EXPR + to that of its initializer. + +2020-04-13 Marek Polacek <polacek@redhat.com> + + PR c++/94588 + * name-lookup.c (check_local_shadow): Add an inform call. + +2020-04-13 Patrick Palka <ppalka@redhat.com> + + PR c++/94521 + * error.c (dump_scope): Pass TFF_NO_FUNCTION_ARGUMENTS to + dump_function_decl when printing a function template instantiation as a + scope. + + PR c++/94470 + * constexpr.c (get_or_insert_ctor_field): Set default value of parameter + 'pos_hint' to -1. + (cxx_eval_bare_aggregate): Use get_or_insert_ctor_field instead of + assuming the the next index belongs at the end of the new CONSTRUCTOR. + (cxx_eval_store_expression): Revert PR c++/78572 fix. + +2020-04-13 Nathan Sidwell <nathan@acm.org> + + PR c++/94426 lambdas with internal linkage are different to no-linkage + * decl2.c (determine_visibility): A lambda's visibility is + affected by its extra scope. + * pt.c (instantiate_decl): Determine var's visibility before + instantiating its initializer. + * tree.c (no_linkage_check): Revert code looking at visibility of + lambda's extra scope. +` +2020-04-10 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94528 + * coroutines.cc (co_await_expander): Remove. + (expand_one_await_expression): New. + (process_one_statement): New. + (await_statement_expander): New. + (build_actor_fn): Revise to use per-statement expander. + (struct susp_frame_data): Reorder and comment. + (register_awaits): Factor code. + (replace_statement_captures): New, factored from... + (maybe_promote_captured_temps):.. here. + (await_statement_walker): Revise to process per statement. + (morph_fn_to_coro): Use revised susp_frame_data layout. + +2020-04-10 Marek Polacek <polacek@redhat.com> + + PR c++/94149 + * method.c (constructible_expr): In C++20, try using parenthesized + initialization of aggregates to determine the result of + __is_constructible. + +2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (co_await_expander): Simplify. + +2020-04-09 Jason Merrill <jason@redhat.com> + + PR c++/94523 + * constexpr.c (cxx_eval_constant_expression) [VAR_DECL]: Look at + ctx->object and ctx->global->values first. + +2020-04-09 Marek Polacek <polacek@redhat.com> + + PR c++/93790 + * call.c (initialize_reference): If the reference binding failed, maybe + try initializing from { }. + * decl.c (grok_reference_init): For T& t(e), set + LOOKUP_AGGREGATE_PAREN_INIT but don't build up a constructor yet. + +2020-04-08 Iain Sandoe <iain@sandoe.co.uk> + Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (maybe_promote_captured_temps): Add a cleanup + expression, if needed, to any call from which we promoted + temporaries captured by reference. + +2020-04-08 Marek Polacek <polacek@redhat.com> + + PR c++/94507 - ICE-on-invalid with lambda template. + * pt.c (tsubst_lambda_expr): Cope when tsubst_template_decl or + tsubst_function_decl returns error_mark_node. + +2020-04-08 Martin Liska <mliska@suse.cz> + + PR c++/94314 + * decl.c (duplicate_decls): Duplicate also DECL_IS_REPLACEABLE_OPERATOR. + (cxx_init_decl_processing): Mark replaceable all implicitly defined + operators. + +2020-04-08 Patrick Palka <ppalka@redhat.com> + + Core issues 1001 and 1322 + PR c++/92010 + * pt.c (rebuild_function_or_method_type): Split function out from ... + (tsubst_function_type): ... here. + (maybe_rebuild_function_decl_type): New function. + (tsubst_function_decl): Use it. + +2020-04-08 Jakub Jelinek <jakub@redhat.com> + + PR c++/94325 + * decl.c (begin_destructor_body): For CLASSTYPE_VBASECLASSES class + dtors, if CLASSTYPE_PRIMARY_BINFO is non-NULL, but not BINFO_VIRTUAL_P, + look at CLASSTYPE_PRIMARY_BINFO of its BINFO_TYPE if it is not + BINFO_VIRTUAL_P, and so on. + +2020-04-08 Marek Polacek <polacek@redhat.com> + + PR c++/94478 - ICE with defaulted comparison operator + * method.c (early_check_defaulted_comparison): Give an error when the + context is null. + +2020-04-08 Tobias Burnus <tobias@codesourcery.com> + + PR middle-end/94120 + * paser.c (cp_parser_oacc_declare): Add check that variables + are declared in the same scope as the directive. + +2020-04-07 Jason Merrill <jason@redhat.com> + + PR c++/94480 + * parser.c (cp_parser_requires_expression): Use tentative_firewall. + + PR c++/94481 + * parser.c (cp_parser_placeholder_type_specifier): Use + matching_parens. + +2020-04-07 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (maybe_promote_captured_temps): Ensure that + reference capture placeholder vars are properly declared. + +2020-04-07 Patrick Palka <ppalka@redhat.com> + + PR c++/90996 + * tree.c (replace_placeholders): Look through all handled components, + not just COMPONENT_REFs. + * typeck2.c (process_init_constructor_array): Propagate + CONSTRUCTOR_PLACEHOLDER_BOUNDARY up from each element initializer to + the array initializer. + +2020-04-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/94512 + * parser.c (cp_parser_omp_parallel): Set OMP_PARALLEL_COMBINED + if cp_parser_omp_master succeeded. + +2020-04-06 Jason Merrill <jason@redhat.com> + + PR c++/94462 + * decl.c (duplicate_decls): Fix handling of DECL_HIDDEN_FRIEND_P. + +2020-04-04 Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/94155 - crash in gimplifier with paren init of aggregates. + * init.c (build_vec_init): Fill in indexes. + +2020-04-04 Jason Merrill <jason@redhat.com> + + PR c++/91377 + * mangle.c (write_expression): Skip IMPLICIT_CONV_EXPR. + +2020-04-04 Patrick Palka <ppalka@redhat.com> + + PR c++/94205 + PR c++/79937 + * constexpr.c (struct constexpr_ctx): New field 'parent'. + (cxx_eval_bare_aggregate): Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY + flag from the original constructor to the reduced constructor. + (lookup_placeholder): Prefer to return the outermost matching object + by recursively calling lookup_placeholder on the 'parent' context, + but don't cross CONSTRUCTOR_PLACEHOLDER_BOUNDARY constructors. + (cxx_eval_constant_expression): Link the 'ctx' context to the 'new_ctx' + context via 'new_ctx.parent' when being expanded without an explicit + target. Don't call replace_placeholders. + (cxx_eval_outermost_constant_expr): Initialize 'ctx.parent' to NULL. + + PR c++/94219 + PR c++/94205 + * constexpr.c (get_or_insert_ctor_field): Split out (while adding + support for VECTOR_TYPEs, and optimizations for the common case) + from ... + (cxx_eval_store_expression): ... here. Rename local variable + 'changed_active_union_member_p' to 'activated_union_member_p'. Record + the sequence of indexes into 'indexes' that yields the subobject we're + assigning to. Record the integer offsets of the constructor indexes + we're assigning through into 'index_pos_hints'. After evaluating the + initializer of the store expression, recompute 'valp' using 'indexes' + and using 'index_pos_hints' as hints. + (cxx_eval_bare_aggregate): Tweak comments. Use get_or_insert_ctor_field + to recompute the constructor_elt pointer we're assigning through after + evaluating each initializer. + +2020-04-04 Jason Merrill <jason@redhat.com> + + PR c++/67825 + * constraint.cc (tsubst_valid_expression_requirement): Call + convert_to_void. + +2020-04-04 Jason Merrill <jason@redhat.com> + + PR c++/94453 + * constexpr.c (maybe_constant_value): Use break_out_target_exprs. + * expr.c (mark_use) [VIEW_CONVERT_EXPR]: Don't wrap a TARGET_EXPR in + NON_LVALUE_EXPR. + +2020-04-04 Jakub Jelinek <jakub@redhat.com> + + PR debug/94441 + * parser.c (cp_parser_omp_for_loop): Use + protected_set_expr_location_if_unset. + * cp-gimplify.c (genericize_if_stmt, genericize_cp_loop): Likewise. + + PR c++/94477 + * pt.c (tsubst_expr) <case OMP_MASTER>: Clear + omp_parallel_combined_clauses. + +2020-04-03 Jason Merrill <jason@redhat.com> + + PR c++/91966 + * pt.c (complex_pack_expansion_r): New. + (complex_alias_template_p): Use it. + +2020-03-31 Jason Merrill <jason@redhat.com> + + PR c++/94205 + * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call + replace_placeholders. + * typeck2.c (store_init_value): Fix arguments to + fold_non_dependent_expr. + +2020-03-31 Jason Merrill <jason@redhat.com> + + * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use + local variables. + +2020-03-30 Jason Merrill <jason@redhat.com> + + PR c++/90711 + * tree.c (cp_tree_equal) [CALL_EXPR]: Compare KOENIG_LOOKUP_P. + (called_fns_equal): Check DECL_CONTEXT. + +2020-03-30 Jakub Jelinek <jakub@redhat.com> + + PR c++/94385 + * semantics.c (add_stmt): Only set STMT_IS_FULL_EXPR_P on trees with + STATEMENT_CODE_P code. + +2020-03-28 Patrick Palka <ppalka@redhat.com> + + PR c++/94306 + * parser.c (cp_parser_requires_clause_opt): Diagnose and recover from + "requires {" when "requires requires {" was probably intended. + + PR c++/94252 + * constraint.cc (tsubst_compound_requirement): Always suppress errors + from type_deducible_p and expression_convertible_p, as they're not + substitution errors. + (diagnose_atomic_constraint) <case INTEGER_CST>: Remove this case so + that we diagnose INTEGER_CST expressions of non-bool type via the + default case. + * cp-gimplify.c (cp_genericize_r) <case REQUIRES_EXPR>: New case. + * parser.c (cp_parser_requires_expression): Always parse the requirement + body as if we're processing a template, by temporarily incrementing + processing_template_decl. Afterwards, if we're not actually in a + template context, perform semantic processing to diagnose any invalid + types and expressions. + * pt.c (tsubst_copy_and_build) <case REQUIRES_EXPR>: Remove dead code. + * semantics.c (finish_static_assert): Explain an assertion failure + when the condition is a REQUIRES_EXPR like we do when it is a concept + check. + + * constraint.cc (diagnose_compound_requirement): When diagnosing a + compound requirement, maybe replay the satisfaction failure, subject to + the current diagnosis depth. + + * constraint.cc (finish_constraint_binary_op): Set the location of EXPR + as well as its range, because build_x_binary_op doesn't always do so. + (current_constraint_diagnosis_depth): New. + (concepts_diagnostics_max_depth_exceeded_p): New. + (collect_operands_of_disjunction): New. + (satisfy_disjunction): When diagnosing a satisfaction failure, maybe + replay each branch of the disjunction, subject to the current diagnosis + depth. + (diagnose_valid_expression): When diagnosing a satisfaction failure, + maybe replay the substitution error, subject to the current diagnosis + recursion. + (diagnose_valid_type): Likewise. + (diagnose_nested_requiremnet): Likewise. + (diagnosing_failed_constraint::diagnosing_failed_constraint): Increment + current_constraint_diagnosis_depth when diagnosing. + (diagnosing_failed_constraint::~diagnosing_failed_constraint): Decrement + current_constraint_diagnosis_depth when diagnosing. + (diagnosing_failed_constraint::replay_errors_p): New static member + function. + (diagnose_constraints): Don't diagnose if concepts_diagnostics_max_depth + is 0. Emit a one-off note to increase -fconcepts-diagnostics-depth if + the limit was exceeded. + * cp-tree.h (diagnosing_failed_constraint::replay_errors_p): Declare. + +2020-03-27 Nathan Sidwell <nathan@acm.org> + + PR c++/84733 + * name-lookup.c (do_pushdecl): Look through cleanp levels. + +2020-03-27 Martin Sebor <msebor@redhat.com> + + PR c++/94078 + PR c++/93824 + PR c++/93810 + * cp-tree.h (most_specialized_partial_spec): Declare. + * parser.c (cp_parser_elaborated_type_specifier): Distinguish alias + from declarations. + (specialization_of): New function. + (cp_parser_check_class_key): Move code... + (class_decl_loc_t::add): ...to here. Add parameters. Avoid issuing + -Wredundant-tags on first-time declarations in other declarators. + Correct handling of template specializations. + (class_decl_loc_t::diag_mismatched_tags): Also expect to be called + when -Wredundant-tags is enabled. Use primary template or partial + specialization as the guide for uses of implicit instantiations. + * pt.c (most_specialized_partial_spec): Declare extern. + +2020-03-27 Nathan Sidwell <nathan@acm.org> + + PR c++/94257 + * name-lookup.c (push_namespace): Triage ambiguous lookups that + contain namespaces. + +2020-03-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/94326 + * call.c (set_flags_from_callee): Don't update + cp_function_chain->can_throw or current_function_returns_abnormally + if cp_unevaluated_operand. + + PR c++/94339 + * cvt.c (ocp_convert): Handle COMPOUND_EXPR by recursion on the second + operand and creating a new COMPOUND_EXPR if anything changed. + +2020-03-26 Marek Polacek <polacek@redhat.com> + + PR c++/94336 - template keyword accepted before destructor names. + * parser.c (cp_parser_unqualified_id): Give an error when 'template' + is followed by a destructor name. + +2020-03-27 Patrick Palka <ppalka@redhat.com> + + * decl.c (compute_array_index_type_loc): Remove redundant + type_dependent_expression_p check that is subsumed by + value_dependent_expression_p. + * decl2.c (is_late_template_attribute): Likewise. + * pt.c (uses_template_parms): Likewise. + (dependent_template_arg_p): Likewise. + +2020-03-26 Marek Polacek <polacek@redhat.com> + + DR 1710 + PR c++/94057 - template keyword in a typename-specifier. + * parser.c (check_template_keyword_in_nested_name_spec): New. + (cp_parser_nested_name_specifier_opt): Implement DR1710, optional + 'template'. Call check_template_keyword_in_nested_name_spec. + (cp_parser_simple_type_specifier): Assume that a < + following a qualified-id in a typename-specifier begins + a template argument list. + +2020-03-26 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (coro_init_identifiers): Initialize an identifier + for the cororoutine handle 'address' method name. + (struct coro_aw_data): Add fields to cover the continuations. + (co_await_expander): Determine the kind of await_suspend in use. + If we have the case that returns a continuation handle, then save + this and make the target for 'scope exit without cleanup' be the + continuation resume label. + (expand_co_awaits): Remove. + (struct suspend_point_info): Remove fields that kept the returned + await_suspend handle type. + (transform_await_expr): Remove code tracking continuation handles. + (build_actor_fn): Add the continuation handle as an actor-function + scope var. Build the symmetric transfer continuation point. Call + the tree walk for co_await expansion directly, rather than via a + trivial shim function. + (register_await_info): Remove fields tracking continuation handles. + (get_await_suspend_return_type): Remove. + (register_awaits): Remove code tracking continuation handles. + (morph_fn_to_coro): Remove code tracking continuation handles. + +2020-03-26 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (co_await_expander): If we are expanding the + initial await expression, set a boolean flag to show that we + have now reached the initial await_resume() method call. + (expand_co_awaits): Handle the 'initial await resume called' flag. + (build_actor_fn): Insert the initial await expression into the + start of the user-authored function-body. Handle the 'initial await + resume called' flag. + (morph_fn_to_coro): Initialise the 'initial await resume called' + flag. Modify the unhandled exception catch clause to recognise + exceptions that occur before the initial await_resume() and re- + throw them. + +2020-03-26 Jakub Jelinek <jakub@redhat.com> + + PR c++/81349 + * class.c (user_provided_p): Use STRIP_TEMPLATE instead of returning + true for all TEMPLATE_DECLs. + + PR c++/94272 + * cp-gimplify.c (cp_genericize_r): Handle STATEMENT_LIST. + +2020-03-25 Patrick Palka <ppalka@redhat.com> + + PR c++/94265 + * parser.c (cp_parser_selection_statement) <case RID_IF>: Invalidate the + current condition chain when the if-statement has a non-empty + init-statement. + +2020-03-25 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/94319 + * coroutines.cc (captures_temporary): Fix a missing dereference. + +2020-03-24 Marek Polacek <polacek@redhat.com> + + PR c++/94190 - wrong no post-decrement operator error in template. + * call.c (convert_like_real): Use convert_from_reference on the result. + +2020-03-24 Jason Merrill <jason@redhat.com> + + PR c++/94186 + * constraint.cc (constraint_satisfaction_value): Repeat noisily on + error. + (tsubst_nested_requirement): Likewise. + (get_constraint_error_location): Allow missing context. + (diagnose_atomic_constraint): Diagnose non-bool constraint here. + (satisfy_atom): Not here. Only diagnose non-constant when noisy. + +2020-03-24 Jason Merrill <jason@redhat.com> + + * pt.c (any_template_parm_r): Look into the type of a non-type + template parm. + +2020-03-24 Jason Merrill <jason@redhat.com> + + * cp-tree.h (cp_expr): When constructing from an expr and a + location, call protected_set_expr_location. + +2020-03-23 Patrick Palka <ppalka@redhat.com> + + PR c++/93805 + * except.c (maybe_noexcept_warning): Add TODO. + * method.c (walk_field_subobs): Pass tf_none to expr_noexcept_p. + +2020-03-23 nathans <nathan@acm.org> + + PR c++/94044 + * tree.c (cp_tree_equal) [SIZEOF_EXPR]: Detect argument pack + operand. + +2020-03-21 Patrick Palka <ppalka@redhat.com> + + PR c++/94066 + * constexpr.c (reduced_constant_expression_p) [CONSTRUCTOR]: Properly + handle unions without an initializer. + (cxx_eval_component_reference): Emit a different diagnostic when the + constructor element corresponding to a union member is NULL. + (cxx_eval_bare_aggregate): When constructing a union, always set the + active union member before evaluating the initializer. Relax assertion + that verifies the index of the constructor element we're initializing + hasn't been changed. + (cxx_eval_store_expression): Diagnose changing the active union member + while the union is in the process of being initialized. After setting + an active union member, clear CONSTRUCTOR_NO_CLEARING on the underlying + CONSTRUCTOR. + (cxx_eval_constant_expression) [PLACEHOLDER_EXPR]: Don't re-reduce a + CONSTRUCTOR returned by lookup_placeholder. + +2020-03-20 Patrick Palka <ppalka@redhat.com> + + * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. Move + the "[with ]" bits to here from ... + (pp_cxx_atomic_constraint): ... here. + * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. + * error.c (rebuild_concept_check): Delete. + (print_concept_check_info): Print the dependent form of the constraint and the + preferably substituted parameter mapping alongside it. + +2020-03-19 Jason Merrill <jason@redhat.com> + + PR c++/94175 + * cp-gimplify.c (simple_empty_class_p): Look through + SIMPLE_TARGET_EXPR_P. + (cp_gimplify_expr) [MODIFY_EXPR]: Likewise. + [RETURN_EXPR]: Avoid producing 'return *retval;'. + * call.c (build_call_a): Strip TARGET_EXPR from empty class arg. + * cp-tree.h (SIMPLE_TARGET_EXPR_P): Check that TARGET_EXPR_INITIAL + is non-null. + +2020-03-19 Jakub Jelinek <jakub@redhat.com> + + PR c++/93931 + * parser.c (cp_parser_omp_var_list_no_open): Call process_outer_var_ref + on outer_automatic_var_p decls. + * cp-gimplify.c (cxx_omp_disregard_value_expr): Return true also for + capture proxy decls. + +2020-03-18 Nathan Sidwell <nathan@acm.org> + + PR c++/94147 - mangling of lambdas assigned to globals + * parser.c (cp_parser_init_declarator): Namespace-scope variables + provide a lambda scope. + * tree.c (no_linkage_check): Lambdas with a variable for extra + scope have a linkage from the variable. + +2020-03-18 Jakub Jelinek <jakub@redhat.com> + + * constraint.cc (resolve_function_concept_check, subsumes_constraints, + strictly_subsumes): Fix up duplicated word issue in a comment. + * coroutines.cc (build_init_or_final_await, captures_temporary): + Likewise. + * logic.cc (dnf_size_r, cnf_size_r): Likewise. + * pt.c (append_type_to_template_for_access_check): Likewise. + + PR c++/91759 + * decl.c (grokfndecl): Restore old diagnostics about deduction + guide declared in different scope if in_namespace is NULL_TREE. + +2020-03-17 Jakub Jelinek <jakub@redhat.com> + + PR c++/90995 + * parser.c (cp_parser_enum_specifier): Use temp_override for + parser->colon_corrects_to_scope_p, replace goto out with return. + If scoped enum or enum with underlying type is not followed by + { or ;, call cp_parser_commit_to_tentative_parse before calling + cp_parser_error and make sure to return error_mark_node instead of + NULL_TREE. Formatting fixes. + +2020-03-17 Ville Voutilainen <ville.voutilainen@gmail.com> + + PR c++/94197 + * method.c (assignable_expr): Use cp_unevaluated. + (is_xible_helper): Push a non-deferred access check for + the stub objects created by assignable_expr and constructible_expr. + +2020-03-17 Jakub Jelinek <jakub@redhat.com> + + * pt.c (tsubst): Fix up duplicated word issue in a diagnostic message. + (lookup_template_class_1, tsubst_expr): Fix up duplicated word issue + in a comment. + * parser.c (cp_parser_statement, cp_parser_linkage_specification, + cp_parser_placeholder_type_specifier, + cp_parser_constraint_requires_parens): Likewise. + * name-lookup.c (suggest_alternative_in_explicit_scope): Likewise. + +2020-03-15 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (co_await_expander): Fix indentation. + +2020-03-14 Jason Merrill <jason@redhat.com> + + PR c++/92068 + * pt.c (process_partial_specialization): Error rather than crash on + extra pack expansion. + +2020-03-14 Jason Merrill <jason@redhat.com> + + PR c++/92909 + * pt.c (find_parameter_packs_r): [DECL_EXPR]: Walk + DECL_ORIGINAL_TYPE of a typedef. + +2020-03-14 Jason Merrill <jason@redhat.com> + + PR c++/93248 + * pt.c (build_deduction_guide): Clear cp_unevaluated_operand for + substituting DECL_ARGUMENTS. + +2020-03-14 Jakub Jelinek <jakub@redhat.com> + + * logic.cc (formula::formula): Change "a an" to "an" in a comment. + * parser.c (cp_debug_parser): Change "a an" to "an" in a string + literal. + +2020-03-13 Patrick Palka <ppalka@redhat.com> + + PR c++/67960 + * call.c (build_over_call): Use a warning_sentinel to disable + warn_deprecated_decl before calling build_addr_func. + +2020-03-12 Jakub Jelinek <jakub@redhat.com> + + PR c++/94124 + * decl.c (reshape_init_array_1): Don't unshare constructor if there + aren't any trailing zero elts, otherwise only unshare the first + nelts. + +2020-03-11 Jason Merrill <jason@redhat.com> + + PR c++/93907 + * constraint.cc (tsubst_parameter_mapping): Canonicalize type + argument. + +2020-03-11 Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/94074 - wrong modifying const object error for COMPONENT_REF. + * constexpr.c (cref_has_const_field): New function. + (modifying_const_object_p): Consider a COMPONENT_REF + const only if any of its fields are const. + (cxx_eval_store_expression): Mark a CONSTRUCTOR of a const type + as readonly after its initialization has been done. + +2020-03-10 Marek Polacek <polacek@redhat.com> + + PR c++/94124 - wrong conversion error with non-viable overload. + * decl.c (reshape_init_array_1): Unshare a constructor if we + stripped trailing zero-initializers. + +2020-03-10 Jason Merrill <jason@redhat.com> + + PR c++/93901 + * pt.c (maybe_instantiate_noexcept): Always update clones. + +2020-03-10 Jason Merrill <jason@redhat.com> + + PR c++/93596 + * pt.c (maybe_aggr_guide): Check BRACE_ENCLOSED_INITIALIZER_P. + +2020-03-10 Jason Merrill <jason@redhat.com> + + PR c++/93922 + PR c++/94041 + PR c++/52320 + PR c++/66139 + * cp-gimplify.c (cp_gimplify_init_expr): Partially revert patch for + 66139: Don't split_nonconstant_init. Remove pre_p parameter. + +2020-03-09 Marek Polacek <polacek@redhat.com> + + PR c++/92031 - bogus taking address of rvalue error. + PR c++/91465 - ICE with template codes in check_narrowing. + PR c++/93870 - wrong error when converting template non-type arg. + PR c++/94068 - ICE with template codes in check_narrowing. + * call.c (convert_like_real): Return IMPLICIT_CONV_EXPR + in a template when not ck_identity and we're dealing with a class. + (convert_like_real) <case ck_ref_bind>: Return IMPLICIT_CONV_EXPR + in a template if we need a temporary. + * decl.c (compute_array_index_type_loc): Remove + instantiate_non_dependent_expr_sfinae call. Call + fold_non_dependent_expr instead of maybe_constant_value. + (build_explicit_specifier): Don't instantiate or create a sentinel + before converting the expression. + * except.c (build_noexcept_spec): Likewise. + * pt.c (convert_nontype_argument): Don't build IMPLICIT_CONV_EXPR. + Set IMPLICIT_CONV_EXPR_NONTYPE_ARG if that's what + build_converted_constant_expr returned. + * typeck2.c (check_narrowing): Call fold_non_dependent_expr instead + of maybe_constant_value. + +2020-03-09 Jakub Jelinek <jakub@redhat.com> + + PR c++/94067 + Revert + 2019-10-11 Paolo Carlini <paolo.carlini@oracle.com> + + * constexpr.c (cxx_eval_constant_expression): Do not handle + RROTATE_EXPR and LROTATE_EXPR. + +2020-03-09 Marek Polacek <polacek@redhat.com> + + PR c++/94050 - ABI issue with alignas on armv7hl. + * class.c (layout_class_type): Don't replace a class's + CLASSTYPE_AS_BASE if their TYPE_USER_ALIGN don't match. + +2020-03-09 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (build_actor_fn): Factor out code inserting the + default return_void call to... + (morph_fn_to_coro): ...here, also hoist local var declarations. + +2020-03-08 Patrick Palka <ppalka@redhat.com> + + PR c++/93729 + * call.c (convert_like_real): Check complain before emitting an error + about binding a bit-field to a reference. + + * cxx-pretty-print.c (cxx_pretty_printer::simple_type_specifier) + [TYPENAME_TYPE]: Print the TYPENAME_TYPE_FULLNAME instead of the + TYPE_NAME. + +2020-03-06 Nathan Sidwell <nathan@acm.org> + + PR c++/94027 + * mangle.c (find_substitution): Don't call same_type_p on template + args that cannot match. + +2020-03-04 Martin Sebor <msebor@redhat.com> + + PR c++/90938 + * tree.c (type_initializer_zero_p): Fail for structs initialized + with non-structs. + +2020-03-04 Jason Merrill <jason@redhat.com> + + PR c++/90432 + * init.c (perform_member_init): Don't do aggregate initialization of + empty field. + * constexpr.c (cx_check_missing_mem_inits): Don't enforce + initialization of empty field. + +2020-03-04 Martin Liska <mliska@suse.cz> + + * method.c: Wrap array in ctor with braces in order + to silent clang warnings. + +2020-03-03 Jason Merrill <jason@redhat.com> + Marek Polacek <polacek@redhat.com> + + PR c++/90505 - mismatch in template argument deduction. + * pt.c (tsubst): Don't reduce the template level of template + parameters when tf_partial. + +2020-03-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/93998 + * constexpr.c (cxx_eval_constant_expression) + <case TARGET_EXPR, case SAVE_EXPR>: Don't record anything if + *non_constant_p is true. + +2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (captures_temporary): Strip component_ref + to its base object. + +2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (finish_co_await_expr): Build co_await_expr + with unknown_type_node. + (finish_co_yield_expr): Ditto. + *pt.c (type_dependent_expression_p): Set co_await/yield_expr + with unknown type as dependent. + +2020-03-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (struct local_var_info): Adjust to remove the + reference to the captured var, and just to note that this is a + lambda capture proxy. + (transform_local_var_uses): Handle lambda captures specially. + (struct param_frame_data): Add a visited set. + (register_param_uses): Also check for param uses in lambda + capture proxies. + (struct local_vars_frame_data): Remove captures list. + (register_local_var_uses): Handle lambda capture proxies by + noting and bypassing them. + (morph_fn_to_coro): Update to remove lifetime extension of + lambda capture-by-copy vars. + +2020-03-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_co_await): Do not build frame + awaitable proxy vars when the co_await expression is + a function parameter or local var. + (co_await_expander): Do not initialise a frame var with + itself. + (transform_await_expr): Only substitute the awaitable + frame var if it's needed. + (register_awaits): Do not make frame copies for param + or local vars that are awaitables. + +2020-02-28 Jason Merrill <jason@redhat.com> + + Implement P2092R0, Disambiguating Nested-Requirements + * parser.c (cp_parser_requirement_parameter_list): Pass + CP_PARSER_FLAGS_TYPENAME_OPTIONAL. + + * call.c (build_user_type_conversion_1): Don't look at the second + conversion of a non-viable candidate. + +2020-02-28 Jakub Jelinek <jakub@redhat.com> + + P1937R2 - Fixing inconsistencies between const{expr,eval} functions + * typeck.c (cp_build_addr_expr_1): Allow taking address of immediate + functions in unevaluated contexts. + +2020-02-27 Nathan Sidwell <nathan@acm.org> + + PR c++/93933 + * pt.c (template_args_equal): Pass ARGUMENT_PACKS through to + cp_tree_equal. + * tree.c (cp_tree_equal): Compare ARGUMENT_PACKS here, + * typeck.c (comptypes): Assert we don't get any argument packs. + + * class.c (adjust_clone_args): Correct arg-checking assert. + * typeck.c (comptypes): Assert not nulls. + +2020-02-26 Marek Polacek <polacek@redhat.com> + + PR c++/93789 - ICE with invalid array bounds. + * decl.c (compute_array_index_type_loc): Don't use the folded + size when folding cleared TREE_CONSTANT. + +2020-02-26 Iain Sandoe <iain@sandoe.co.uk> + + * class.c (classtype_has_non_deleted_copy_ctor): New. + * coroutines.cc (struct param_info): Keep track of params + that are references, and cache the original type and whether + the DTOR is trivial. + (build_actor_fn): Handle param copies always, and adjust the + handling for references. + (register_param_uses): Only handle uses here. + (classtype_has_non_deleted_copy_ctor): New. + (morph_fn_to_coro): Adjust param copy handling to match n4849 + by reordering ahead of the promise CTOR and always making a + frame copy, even if the param is unused in the coroutine body. + * cp-tree.h (classtype_has_non_deleted_copy_ctor): New. + +2020-02-26 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (finish_constraint_binary_op): Set expr's location range + to the range of its operands. + (satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint. + (diagnose_trait_expr): Take the instantiated parameter mapping MAP + instead of the corresponding template arguments ARGS and adjust body + accordingly. + (diagnose_requires_expr): Likewise. + (diagnose_atomic_constraint): Likewise. When printing an atomic + constraint expression, print the instantiated parameter mapping + alongside it. + * cxx-pretty-print.cc (cxx_pretty_printer::expression) + [NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK. + (cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK. + +2020-02-26 Marek Polacek <polacek@redhat.com> + + PR c++/93676 - value-init crash in template. + * init.c (build_new_1): Don't call build_vec_init in a template. + +2020-02-26 Marek Polacek <polacek@redhat.com> + + PR c++/93862 - ICE with static_cast when converting from int[]. + * call.c (reference_compatible_p): No longer static. + * cp-tree.h (reference_compatible_p): Declare. + * typeck.c (build_static_cast_1): Use reference_compatible_p instead + of reference_related_p. + +2020-02-26 Marek Polacek <polacek@redhat.com> + + PR c++/93803 - ICE with constexpr init and [[no_unique_address]]. + * constexpr.c (reduced_constant_expression_p): Don't crash on a null + field. + +2020-02-24 Martin Sebor <msebor@redhat.com> + + PR c++/93804 + * parser.c (cp_parser_check_class_key): Avoid issuing -Wredundant-tags + in shared C/C++ code in headers. + Remove a duplicate hunk of code. + +2020-02-24 Marek Polacek <polacek@redhat.com> + + PR c++/93869 - ICE with -Wmismatched-tags. + * parser.c (cp_parser_check_class_key): Check class_key earlier. + +2020-02-24 Marek Polacek <polacek@redhat.com> + + PR c++/93712 - ICE with ill-formed array list-initialization. + * call.c (next_conversion): Return NULL for ck_aggr. + (build_aggr_conv): Set u.expr instead of u.next. + (build_array_conv): Likewise. + (build_complex_conv): Likewise. + (conv_get_original_expr): Handle ck_aggr. + +2020-02-24 Jakub Jelinek <jakub@redhat.com> + + P1937R2 - Fixing inconsistencies between const{expr,eval} functions + * call.c (build_over_call): Don't evaluate immediate functions in + unevaluated operands. + +2020-02-24 Jason Merrill <jason@redhat.com> + + P0780R2: Resolve lambda init-capture pack grammar. + * parser.c (cp_parser_lambda_introducer): Expect &...x=y rather than + ...&x=y. + +2020-02-22 Marek Polacek <polacek@redhat.com> + + PR c++/93882 + * decl.c (grokdeclarator): Use %qs in a diagnostic message. + +2020-02-21 Martin Sebor <msebor@redhat.com> + + PR gcov-profile/93753 + * class.c (check_flexarrays): Tighten up a test for potential members + of anonymous structs or unions. + +2020-02-20 Martin Sebor <msebor@redhat.com> + + PR c++/93801 + * parser.c (cp_parser_check_class_key): Only handle true C++ class-keys. + +2020-02-20 Martin Liska <mliska@suse.cz> + + PR translation/93841 + * config/or1k/or1k.opt: Remove superfluous word. + * doc/invoke.texi: Likewise. + +2020-02-20 Martin Liska <mliska@suse.cz> + + PR translation/93838 + * parser.c (cp_parser_decl_specifier_seq): Remove trailing space. + +2020-02-19 Marek Polacek <polacek@redhat.com> + + PR c++/93169 - wrong-code with a non-constexpr constructor. + * constexpr.c (cxx_eval_call_expression): Only set TREE_READONLY + on constant CONSTRUCTORs. + +2020-02-15 Marek Polacek <polacek@redhat.com> + + PR c++/93710 - poor diagnostic for array initializer. + * call.c (build_user_type_conversion_1): Use cp_expr_loc_or_input_loc + for an error call. + +2020-02-15 Jason Merrill <jason@redhat.com> + + PR c++/92556 + * pt.c (any_template_parm_r): Look into lambda body. + + PR c++/92583 + * pt.c (any_template_parm_r): Remove CONSTRUCTOR handling. + +2020-02-14 Jakub Jelinek <jakub@redhat.com> + + PR c++/61414 + * class.c (enum_min_precision): Change prec type from int to int &. + + PR libstdc++/92906 + * cp-tree.h (enum cp_tree_index): Add CPTI_FALLBACK_DFLOAT32_TYPE, + CPTI_FALLBACK_DFLOAT64_TYPE and CPTI_FALLBACK_DFLOAT128_TYPE. + (fallback_dfloat32_type, fallback_dfloat64_type, + fallback_dfloat128_type): Define. + * mangle.c (write_builtin_type): Handle fallback_dfloat*_type like + dfloat*_type_node. + * rtti.c (emit_support_tinfos): Emit DFP typeinfos even when dfp + is disabled for compatibility. + +2020-02-13 Jason Merrill <jason@redhat.com> + + PR c++/93713 + * name-lookup.c (matching_fn_p): A function does not match a + template. + + PR c++/93643 + PR c++/91476 + * tree.c (decl_linkage): Always lk_none for locals. + +2020-02-12 Jason Merrill <jason@redhat.com> + + PR c++/92583 + PR c++/92654 + * tree.c (cp_walk_subtrees): Walk CONSTRUCTOR types here. + * pt.c (find_parameter_packs_r): Not here. + +2020-02-12 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Implement deallocation function + selection per n4849, dcl.fct.def.coroutine bullet 12. + (morph_fn_to_coro): Implement allocation function selection per + n4849, dcl.fct.def.coroutine bullets 9 and 10. + +2020-02-12 Marek Polacek <polacek@redhat.com> + + PR c++/93684 - ICE-on-invalid with broken attribute. + * parser.c (cp_parser_std_attribute): Peek a token first before + consuming it. + +2020-02-11 Jason Merrill <jason@redhat.com> + + PR c++/93675 + * class.c (add_implicitly_declared_members): Use do_friend. + * method.c (implicitly_declare_fn): Fix friend handling. + (decl_remember_implicit_trigger_p): New. + (synthesize_method): Use it. + * decl2.c (mark_used): Use it. + +2020-02-11 Jason Merrill <jason@redhat.com> + + PR c++/93650 + PR c++/90691 + * constexpr.c (maybe_constant_value): Correct earlier change. + (cxx_eval_binary_expression) [SPACESHIP_EXPR]: Pass lval through. + * method.c (genericize_spaceship): Wrap result in TARGET_EXPR. + +2020-02-12 Patrick Palka <ppalka@redhat.com> + + PR c++/69448 + PR c++/80471 + * type-utils.h (find_type_usage): Refactor to take a tree * and to + return a tree *, and update documentation accordingly. + * pt.c (make_auto_1): Set AUTO_IS_DECLTYPE when building a + decltype(auto) node. + (make_constrained_decltype_auto): No need to explicitly set + AUTO_IS_DECLTYPE anymore. + (splice_late_return_type): Use find_type_usage to find and + replace a possibly nested auto node instead of using is_auto. + Check test for is_auto into an assert when deciding whether + to late_return_type. + (type_uses_auto): Adjust the call to find_type_usage. + * parser.c (cp_parser_decltype): No need to explicitly set + AUTO_IS_DECLTYPE anymore. + + * error.c (dump_decl) [CONCEPT_DECL]: Use dump_simple_decl. + (dump_simple_decl): Handle standard concept definitions as well as + variable concept definitions. + +2020-02-10 Jakub Jelinek <jakub@redhat.com> + + PR other/93641 + * error.c (dump_decl_name): Fix up last argument to strncmp. + +2020-02-10 Jason Merrill <jason@redhat.com> + + PR c++/93618 + * tree.c (array_of_unknown_bound_p): New. + * init.c (perform_member_init): Do nothing for flexible arrays. + +2020-02-09 Jakub Jelinek <jakub@redhat.com> + + PR c++/93633 + * constexpr.c (cxx_eval_constant_expression): If obj is heap var with + ARRAY_TYPE, use the element type. Punt if objtype after that is not + a class type. + +2020-02-08 Jason Merrill <jason@redhat.com> + + PR c++/90691 + * expr.c (fold_for_warn): Call maybe_constant_value. + * constexpr.c (struct constexpr_ctx): Add uid_sensitive bit-field. + (maybe_constant_value): Add uid_sensitive parm. + (get_fundef_copy): Don't copy if it's true. + (cxx_eval_call_expression): Don't instantiate if it's true. + (cxx_eval_outermost_constant_expr): Likewise. + + PR c++/92852 + * constexpr.c (maybe_constant_value): Don't unshare if the cached + value is the same as the argument. + + * typeck.c (maybe_warn_about_returning_address_of_local): Add + location parameter. + + * typeck2.c (process_init_constructor): Also clear TREE_SIDE_EFFECTS + if appropriate. + +2020-02-08 Jakub Jelinek <jakub@redhat.com> + + PR c++/93549 + * constexpr.c (find_array_ctor_elt): If last element has no index, + for flag_checking verify all elts have no index. If i is within the + elts, return it directly, if it is right after the last elt, append + if NULL index, otherwise force indexes on all elts. + (cxx_eval_store_expression): Allow cep->index to be NULL. + +2020-02-07 Marek Polacek <polacek@redhat.com> + + PR c++/92947 - Paren init of aggregates in unevaluated context. + * call.c (build_new_method_call_1): Don't check + cp_unevaluated_operand. Check the return value of digest_init. + +2020-02-06 Jason Merrill <jason@redhat.com> + + PR c++/92654 + * tree.c (cp_walk_subtrees): Walk into type template arguments. + * cp-tree.h (TYPE_TEMPLATE_INFO_MAYBE_ALIAS): Use typedef_variant_p + instead of TYPE_ALIAS_P. + * pt.c (push_template_decl_real): Likewise. + (find_parameter_packs_r): Likewise. Remove dead code. + * error.c (find_typenames_r): Remove dead code. + +2020-02-06 Jason Merrill <jason@redhat.com> + + PR c++/92517 + * parser.c (cp_parser_constraint_primary_expression): Do the main + parse non-tentatively. + +2020-02-06 Marek Polacek <polacek@redhat.com> + + PR c++/93597 - ICE with lambda in operator function. + * name-lookup.c (maybe_save_operator_binding): Check is_overloaded_fn. + +2020-02-05 Jason Merrill <jason@redhat.com> + + PR c++/93140 + * pt.c (tsubst_decl) [PARM_DECL]: Check cp_unevaluated_operand in + handling of TREE_CHAIN for empty pack. + +2020-02-05 Jakub Jelinek <jakub@redhat.com> + + PR c++/93557 + * semantics.c (cp_build_vec_convert): Call decay_conversion on arg + prior to passing it to c_build_vec_convert. + +2020-02-05 Marek Polacek <polacek@redhat.com> + + PR c++/93559 - ICE with CONSTRUCTOR flags verification. + * decl.c (reshape_init_array_1): Don't reuse a CONSTRUCTOR with + TREE_SIDE_EFFECTS. + +2020-02-05 Jason Merrill <jason@redhat.com> + + PR c++/92593 + * decl.c (grokdeclarator): Reject field of current class type even + in a template. + +2020-02-05 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (maybe_promote_captured_temps): Increase the index + number for temporary variables' name. + +2020-02-05 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (build_co_await): Call convert_from_reference + to wrap co_await_expr with indirect_ref which avoid + reference/non-reference type confusion. + + (co_await_expander): Sink to call_expr if await_resume + is wrapped by indirect_ref. + +2020-02-04 Jason Merrill <jason@redhat.com> + + PR c++/93551 + * constraint.cc (satisfy_declaration_constraints): Check return + value of push_tinst_level. + + PR c++/90951 + * constexpr.c (cxx_eval_array_reference): {}-initialize missing + elements instead of value-initializing them. + + PR c++/86917 + * init.c (perform_member_init): Simplify. + * constexpr.c (cx_check_missing_mem_inits): Allow uninitialized + flexarray. + (cxx_eval_vec_init_1): Handle CONSTRUCTOR. + +2020-02-04 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (find_promise_type): Delete unused forward + declaration. + (struct coroutine_info): Add a bool for no promise type error. + (coro_promise_type_found_p): Only emit the error for a missing + promise once in each affected coroutine. + +2020-02-03 Jason Merrill <jason@redhat.com> + + PR c++/66477 + * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't + defer loading the value of a reference. + +2020-02-03 Jason Merrill <jason@redhat.com> + + PR c++/91953 + * constexpr.c (potential_constant_expression_1) [PARM_DECL]: Allow + empty class type. + [COMPONENT_REF]: A member function reference doesn't use the object + as an rvalue. + +2020-02-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/93458 + * coroutines.cc (struct coroutine_info): Add a bool flag to note + that we emitted an error for a bad function return type. + (get_coroutine_info): Tolerate an unset info table in case of + missing traits. + (find_coro_traits_template_decl): In case of error or if we didn't + find a type template, note we emitted the error and suppress + duplicates. + (find_coro_handle_template_decl): Likewise. + (instantiate_coro_traits): Only check for error_mark_node in the + return from lookup_qualified_name. + (coro_promise_type_found_p): Reorder initialization so that we check + for the traits and their usability before allocation of the info + table. Check for a suitable return type and emit a diagnostic for + here instead of relying on the lookup machinery. This allows the + error to have a better location, and means we can suppress multiple + copies. + (coro_function_valid_p): Re-check for a valid promise (and thus the + traits) before proceeding. Tolerate missing info as a fatal error. + +2020-02-03 Jason Merrill <jason@redhat.com> + + PR c++/88256 + * cp-gimplify.c (predeclare_vla): New. + (cp_genericize_r) [NOP_EXPR]: Call it. + +2020-02-03 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (transform_await_wrapper): Set actor funcion as + new context of label_decl. + (build_actor_fn): Fill new field of await_xform_data. + +2020-02-02 Marek Polacek <polacek@redhat.com> + + PR c++/93530 - ICE on invalid alignas in a template. + * decl.c (grokdeclarator): Call cplus_decl_attributes instead of + decl_attributes. + +2020-01-31 Jason Merrill <jason@redhat.com> + + PR c++/86216 + * semantics.c (process_outer_var_ref): Capture VLAs even in + unevaluated context. + + PR c++/14179 + * decl.c (reshape_init_array_1): Reuse a single CONSTRUCTOR with + non-aggregate elements. + (reshape_init_array): Add first_initializer_p parm. + (reshape_init_r): Change first_initializer_p from bool to tree. + (reshape_init): Pass init to it. + + PR c++/14179 + * parser.c (cp_parser_initializer_list): Suppress location wrappers + after 256 elements. + +2020-01-29 Jason Merrill <jason@redhat.com> + + PR c++/82521 + * pt.c (tsubst_copy_and_build) [EQ_EXPR]: Only suppress warnings if + the expression was dependent before substitution. + +2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (act_des_fn): New. + (morph_fn_to_coro): Call act_des_fn to build actor/destroy decls. + Access promise via actor function's frame pointer argument. + (build_actor_fn, build_destroy_fn): Use frame pointer argument. + +2020-01-30 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (co_await_expander): Handle type conversion case. + +2020-01-29 Jason Merrill <jason@redhat.com> + + PR c++/90333 + PR c++/89640 + PR c++/60503 + * parser.c (cp_parser_type_specifier_seq): Don't parse attributes in + a trailing return type. + (cp_parser_lambda_declarator_opt): Parse C++11 attributes before + parens. + +2020-01-29 Marek Polacek <polacek@redhat.com> + + PR c++/91754 - Fix template arguments comparison with class NTTP. + * pt.c (class_nttp_const_wrapper_p): New. + (template_args_equal): See through class_nttp_const_wrapper_p + arguments. + +2020-01-29 Marek Polacek <polacek@redhat.com> + + PR c++/92948 - Fix class NTTP with template arguments. + * pt.c (convert_nontype_argument): Use IMPLICIT_CONV_EXPR when + converting a value-dependent expression to a class type. + (tsubst_copy) <case VIEW_CONVERT_EXPR>: Allow IMPLICIT_CONV_EXPR + as the result of the tsubst_copy call. + +2020-01-29 Jakub Jelinek <jakub@redhat.com> + + PR c++/91118 + * cp-gimplify.c (cxx_omp_predetermined_sharing): Return + OMP_CLAUSE_DEFAULT_SHARED for typeinfo decls. + +2020-01-28 Jason Merrill <jason@redhat.com> + + PR c++/93442 + * parser.c (cp_parser_lambda_expression): Clear in_discarded_stmt. + + PR c++/93477 + PR c++/91476 + * decl2.c (copy_linkage): Do copy DECL_ONE_ONLY and DECL_WEAK. + + PR c++/90546 + * call.c (build_user_type_conversion_1): Allow a template conversion + returning an rvalue reference to bind directly to an lvalue. + + PR c++/90731 + * decl.c (grokdeclarator): Propagate eh spec from typedef. + +2020-01-28 Martin Liska <mliska@suse.cz> + + PR c++/92440 + * pt.c (redeclare_class_template): Group couple of + errors and inform messages with auto_diagnostic_group. + +2020-01-28 Martin Liska <mliska@suse.cz> + + PR c++/92440 + * pt.c (redeclare_class_template): Use inform + for the second location. + +2020-01-27 Jason Merrill <jason@redhat.com> + + PR c++/90966 + * pt.c (tsubst_copy) [STRING_CST]: Don't use fold_convert. + +2020-01-27 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/93443 + * coroutines.cc (morph_fn_to_coro): Check the ramp return + value when it is constructed from the 'get return object'. + +2020-01-27 Nathan Sidwell <nathan@acm.org> + + PR c++/91826 + * name-lookup.c (is_ancestor): Allow CHILD to be a namespace alias. + +2020-01-26 Jason Merrill <jason@redhat.com> + + PR c++/90992 + * except.c (maybe_noexcept_warning): Check DECL_IN_SYSTEM_HEADER and + temporarily enable -Wsystem-headers. Change second warning to + conditional inform. + + PR c++/90997 + * semantics.c (finish_call_expr): Don't call + instantiate_non_dependent_expr before warn_for_memset. + +2020-01-25 Marek Polacek <polacek@redhat.com> + + PR c++/93414 - poor diagnostic for dynamic_cast in constexpr context. + * constexpr.c (cxx_eval_dynamic_cast_fn): Add a reference + dynamic_cast diagnostic. + +2020-01-24 Jason Merrill <jason@redhat.com> + + PR c++/93400 - ICE with constrained friend. + * constraint.cc (maybe_substitute_reqs_for): New. + * decl.c (function_requirements_equivalent_p): Call it. + * pt.c (tsubst_friend_function): Only substitute + TEMPLATE_PARMS_CONSTRAINTS. + (tsubst_template_parms): Copy constraints. + +2020-01-24 Jason Merrill <jason@redhat.com> + + PR c++/93279 - ICE with lambda in member operator. + * name-lookup.c (maybe_save_operator_binding): Don't remember + class-scope bindings. + +2020-01-24 Jason Merrill <jason@redhat.com> + + PR c++/93377 - ICE with member alias in constraint. + * pt.c (any_template_parm_r): Look at template arguments for all + aliases, not only alias templates. + +2020-01-24 Marek Polacek <polacek@redhat.com> + + PR c++/93299 - ICE in tsubst_copy with parenthesized expression. + * pt.c (tsubst_copy): Handle a REF_PARENTHESIZED_P VIEW_CONVERT_EXPR. + +2020-01-24 Jason Merrill <jason@redhat.com> + + PR c++/92852 - ICE with generic lambda and reference var. + * constexpr.c (maybe_constant_value): Likewise. + +2020-01-23 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/92804 + * parser.c (cp_parser_nested_name_specifier_opt): Properly + diagnose concept-ids. + +2020-01-23 Jason Merrill <jason@redhat.com> + + PR c++/93331 - ICE with __builtin_strchr. + * constexpr.c (cxx_eval_builtin_function_call): Use the original + argument if we didn't manage to extract a STRING_CST. + + PR c++/93345 - ICE with defaulted dtor and template. + PR c++/33799 + * decl.c (cxx_maybe_build_cleanup): Don't try to set + throwing_cleanup in a template. + +2020-01-22 Marek Polacek <polacek@redhat.com> + + PR c++/92907 - noexcept does not consider "const" in member functions. + * g++.dg/cpp0x/noexcept56.C: New test. + +2020-01-22 Marek Polacek <polacek@redhat.com> + + PR c++/93324 - ICE with -Wall on constexpr if. + * semantics.c (is_std_constant_evaluated_p): Check fndecl. + +2020-01-22 Patrick Palka <ppalka@redhat.com> + + * constraint.cc (get_mapped_args): Avoid using auto_vec + as a vector element. Release the vectors inside the lists + vector. + * parser.c (cp_literal_operator_id): Free the buffer. + +2020-01-22 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (finish_co_await_expr): Add error check on return + value of build_co_await. + (finish_co_yield_expr,): Ditto. + +2020-01-22 Jun Ma <JunMa@linux.alibaba.com> + + * coroutines.cc (lookup_awaitable_member): Lookup an awaitable member. + (lookup_promise_method): Emit diagnostic when get NULL_TREE back only. + (build_co_await): Use lookup_awaitable_member instead of lookup_member. + +2020-01-21 Jason Merrill <jason@redhat.com> + + PR c++/60855 - ICE with sizeof VLA capture. + * lambda.c (is_lambda_ignored_entity): Don't look past VLA capture. + + PR c++/90732 - ICE with VLA capture and generic lambda. + * pt.c (tsubst_lambda_expr): Repeat add_capture for VLAs. + +2020-01-21 Iain Sandoe <iain@sandoe.co.uk> + Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (coro_promise_type_found_p): Check for NULL return + from complete_type_or_else. + (register_param_uses): Likewise. + (build_co_await): Do not try to use complete_type_or_else for void + types, otherwise for incomplete types, check for NULL return from + complete_type_or_else. + +2020-01-21 Jason Merrill <jason@redhat.com> + + PR c++/91476 - anon-namespace reference temp clash between TUs. + * decl2.c (copy_linkage): Factor out of get_guard. + * call.c (make_temporary_var_for_ref_to_temp): Use it. + * decl.c (cp_finish_decomp): Use it. + (cp_finish_decl): determine_visibility sooner. + +2020-01-21 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (finish_co_await_expr): Set return value flag. + (finish_co_yield_expr, morph_fn_to_coro): Ditto. + +2020-01-19 Jason Merrill <jason@redhat.com> + + PR c++/33799 - destroy return value, take 2. + * cp-tree.h (current_retval_sentinel): New macro. + (struct language_function): Add throwing_cleanup bitfield. + * decl.c (cxx_maybe_build_cleanup): Set it. + * except.c (maybe_set_retval_sentinel) + (maybe_splice_retval_cleanup): New functions. + * parser.c (cp_parser_compound_statement): Call + maybe_splice_retval_cleanup. + * typeck.c (check_return_expr): Call maybe_set_retval_sentinel. + + * parser.c (cp_parser_lambda_body): Use cp_parser_function_body. + +2020-01-18 Jakub Jelinek <jakub@redhat.com> + + * coroutines.cc (get_fn_local_identifier): Fix NO_DOT_IN_LABEL + but non-NO_DOLLAR_IN_LABEL case build. + +2020-01-18 Iain Sandoe <iain@sandoe.co.uk> + + * Make-lang.in: Add coroutines.o. + * cp-tree.h (lang_decl-fn): coroutine_p, new bit. + (DECL_COROUTINE_P): New. + * lex.c (init_reswords): Enable keywords when the coroutine flag + is set, + * operators.def (co_await): New operator. + * call.c (add_builtin_candidates): Handle CO_AWAIT_EXPR. + (op_error): Likewise. + (build_new_op_1): Likewise. + (build_new_function_call): Validate coroutine builtin arguments. + * constexpr.c (potential_constant_expression_1): Handle + CO_AWAIT_EXPR, CO_YIELD_EXPR, CO_RETURN_EXPR. + * coroutines.cc: New file. + * cp-objcp-common.c (cp_common_init_ts): Add CO_AWAIT_EXPR, + CO_YIELD_EXPR, CO_RETRN_EXPR as TS expressions. + * cp-tree.def (CO_AWAIT_EXPR, CO_YIELD_EXPR, (CO_RETURN_EXPR): New. + * cp-tree.h (coro_validate_builtin_call): New. + * decl.c (emit_coro_helper): New. + (finish_function): Handle the case when a function is found to + be a coroutine, perform the outlining and emit the outlined + functions. Set a bit to signal that this is a coroutine component. + * parser.c (enum required_token): New enumeration RT_CO_YIELD. + (cp_parser_unary_expression): Handle co_await. + (cp_parser_assignment_expression): Handle co_yield. + (cp_parser_statement): Handle RID_CO_RETURN. + (cp_parser_jump_statement): Handle co_return. + (cp_parser_operator): Handle co_await operator. + (cp_parser_yield_expression): New. + (cp_parser_required_error): Handle RT_CO_YIELD. + * pt.c (tsubst_copy): Handle CO_AWAIT_EXPR. + (tsubst_expr): Handle CO_AWAIT_EXPR, CO_YIELD_EXPR and + CO_RETURN_EXPRs. + * tree.c (cp_walk_subtrees): Likewise. + +2020-01-17 Jason Merrill <jason@redhat.com> + + PR c++/92531 - ICE with noexcept(lambda). + * pt.c (uses_template_parms): Don't try to enumerate all the + expression cases. + +2020-01-17 Jakub Jelinek <jakub@redhat.com> + + PR c++/93228 + * parser.c (cp_parser_template_name): Look up deprecated attribute + in DECL_TEMPLATE_RESULT or its type's attributes. + +2020-01-16 Jason Merrill <jason@redhat.com> + + PR c++/93286 - ICE with __is_constructible and variadic template. + * pt.c (tsubst) [TREE_LIST]: Handle pack expansion. + (tsubst_copy_and_build) [TRAIT_EXPR]: Always use tsubst for type2. + + PR c++/93280 - ICE with aggregate assignment and DMI. + * init.c (get_nsdmi): Set TARGET_EXPR_DIRECT_INIT_P here. + * typeck2.c (digest_nsdmi_init): Not here. + +2020-01-15 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/91073 + * cp-tree.h (is_constrained_auto): New. + * parser.c (cp_parser_maybe_commit_to_declaration): Correctly + handle concept-check expressions; take a cp_decl_specifier_seq* + instead of a bool. + (cp_parser_condition): Update call. + (cp_parser_simple_declaration): Likewise. + (cp_parser_placeholder_type_specifier): Correctly handle + concept-check expressions. + +2020-01-15 Jason Merrill <jason@redhat.com> + + Revert + PR c++/33799 - destroy return value if local cleanup throws. + * cp-tree.h (current_retval_sentinel): New macro. + * decl.c (start_preparsed_function): Set up cleanup for retval. + * typeck.c (check_return_expr): Set current_retval_sentinel. + + PR c++/93257 - consteval void function. + * constexpr.c (verify_constant): Allow void_node. + + PR c++/92871 - bad code with xvalue and GNU ?: extension. + * call.c (prevent_lifetime_extension): New. + (build_conditional_expr_1): Use it. + +2020-01-14 Nathan Sidwell <nathan@acm.org> + + PR c++/90916 + * pt.c (retrieve_specialization): Use get_template_info, not open + coding access. + + PR c++/90916 + * pt.c (retrieve_specialization): Get the TI from the decl or the + classtype as appropriate. + +2020-01-14 David Malcolm <dmalcolm@redhat.com> + + * cp-gimplify.c (source_location_table_entry_hash::empty_zero_p): + New static constant. + * cp-tree.h (named_decl_hash::empty_zero_p): Likewise. + (struct named_label_hash::empty_zero_p): Likewise. + * decl2.c (mangled_decl_hash::empty_zero_p): Likewise. + +2020-01-14 Jason Merrill <jason@redhat.com> + + PR c++/92590 - wrong handling of inherited default ctor. + * class.c (add_method): A constrained inherited ctor doesn't hide an + implicit derived ctor. + Revert: + PR c++/92552 - ICE with inherited constrained default ctor. + * pt.c (instantiate_class_template_1): Copy + TYPE_HAS_USER_CONSTRUCTOR. + PR c++/91930 - ICE with constrained inherited default ctor. + * name-lookup.c (do_class_using_decl): Set TYPE_HAS_USER_CONSTRUCTOR + for inherited constructor. + PR c++/92594 - ICE with inherited trivial default ctor. + * method.c (trivial_fn_p): Treat an inherited default constructor + like a normal default constructor. + + PR c++/92594 - ICE with inherited trivial default ctor. + * method.c (trivial_fn_p): Treat an inherited default constructor + like a normal default constructor. + + PR c++/92009 - ICE with punning of typeid. + * rtti.c (get_tinfo_desc): Call xref_basetypes. + * constexpr.c (cxx_fold_indirect_ref): Don't strip + REINTERPRET_CAST_P. + +2020-01-13 Jason Merrill <jason@redhat.com> + + PR c++/92746 - ICE with noexcept of function concept check. + * except.c (check_noexcept_r): Handle concept-check. + + PR c++/92582 - ICE with member template as requirement. + * pt.c (struct find_template_parameter_info): Add ctx_parms. + (any_template_parm_r): Handle TEMPLATE_DECL. + (find_template_parameters): Take parms instead of their depth. + * constraint.cc (build_parameter_mapping): Pass them. + + PR c++/33799 - destroy return value if local cleanup throws. + * cp-tree.h (current_retval_sentinel): New macro. + * decl.c (start_preparsed_function): Set up cleanup for retval. + * typeck.c (check_return_expr): Set current_retval_sentinel. + + PR c++/93238 - short right-shift with enum. + * typeck.c (cp_build_binary_op): Use folded op1 for short_shift. + +2020-01-10 Jason Merrill <jason@redhat.com> + + * typeck.c (cp_build_binary_op): Restore short_shift code. + + PR c++/93143 - incorrect tree sharing with constexpr. + * constexpr.c (cxx_eval_outermost_constant_expr): Don't assume + CONSTRUCTORs are already unshared. + + PR c++/93173 - incorrect tree sharing. + PR c++/93033 + * cp-gimplify.c (cp_gimplify_init_expr, cp_gimplify_expr): Use + copy_if_shared after cp_genericize_tree. + * typeck2.c (split_nonconstant_init): Don't unshare here. + +2020-01-08 Jason Merrill <jason@redhat.com> + + * cp-gimplify.c (cp_gimplify_expr) [TARGET_EXPR]: Check + TARGET_EXPR_DIRECT_INIT_P. + * constexpr.c (cxx_eval_constant_expression): Likewise. + +2020-01-08 Jason Merrill <jason@redhat.com> + + PR c++/91369 - constexpr destructor and member initializer. + * constexpr.c (cxx_eval_store_expression): Look through TARGET_EXPR + when not preevaluating. + +2020-01-08 Jason Merrill <jason@redhat.com> + + * constexpr.c (cxx_eval_call_expression): Remove DECL_BY_REFERENCE + support. + +2020-01-07 Paolo Carlini <paolo.carlini@oracle.com> + + * init.c (build_new): Add location_t parameter and use it throughout. + (build_raw_new_expr): Likewise. + * parser.c (cp_parser_new_expression): Pass the combined_loc. + * pt.c (tsubst_copy_and_build): Adjust call. + * cp-tree.h: Update declarations. + +2020-01-07 Jason Merrill <jason@redhat.com> + + PR c++/47877 - -fvisibility-inlines-hidden and member templates. + * decl2.c (determine_visibility): -fvisibility-inlines-hidden beats + explicit class visibility for a template. + +2020-01-07 Richard Sandiford <richard.sandiford@arm.com> + + * mangle.c (mangle_type_attribute_p): New function, split out from... + (write_CV_qualifiers_for_type): ...here. Don't mangle attributes + that contain a space. + +2020-01-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/91369 + * constexpr.c (struct constexpr_global_ctx): Add heap_alloc_count + member, initialize it to zero in ctor. + (cxx_eval_call_expression): Bump heap_dealloc_count when deleting + a heap object. Don't cache calls to functions which allocate some + heap objects and don't deallocate them or deallocate some heap + objects they didn't allocate. + +2020-01-06 Jason Merrill <jason@redhat.com> + + PR c++/92552 - ICE with inherited constrained default ctor. + * pt.c (instantiate_class_template_1): Copy + TYPE_HAS_USER_CONSTRUCTOR. + * class.c (one_inherited_ctor): Don't set it here. + +2020-01-06 Andrew Sutton <asutton@lock3software.com> + + PR c++/92739 - parsing requires clause with attributes. + * parser.c (cp_parser_constraint_requires_parens): Exclude + attributes as postfix expressions. + +2020-01-05 Jakub Jelinek <jakub@redhat.com> + + PR c++/93138 + * parser.c (cp_parser_check_class_key): Disable access checks for the + simple name lookup. + (cp_parser_maybe_warn_enum_key): Likewise. Return early if + !warn_redundant_tags. + +2010-01-05 Jakub Jelinek <jakub@redhat.com> + + PR c++/93046 + * cp-gimplify.c (cp_gimplify_init_expr): Don't look through + TARGET_EXPR if it has been gimplified already. + +2020-01-03 Jason Merrill <jason@redhat.com> + + PR c++/93033 - incorrect tree node sharing with array init. + * typeck2.c (split_nonconstant_init): Unshare non-decl. + * cp-gimplify.c (cp_gimplify_init_expr): Only split if -fexceptions. + +2020-01-02 Jason Merrill <jason@redhat.com> + + * pt.c (invalid_nontype_parm_type_p): Reject class placeholder in + C++17. + +2020-01-02 Jakub Jelinek <jakub@redhat.com> + + PR c/90677 + * cp-objcp-common.c (identifier_global_tag): Return NULL_TREE if name + has not been found, rather than error_mark_node. + +2020-01-01 Jakub Jelinek <jakub@redhat.com> + + Update copyright years. + +Copyright (C) 2020 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index ebfdc90..62295fb 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -1,5 +1,5 @@ # Top level -*- makefile -*- fragment for GNU C++. -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. #This file is part of GCC. @@ -57,6 +57,16 @@ CFLAGS-cp/g++spec.o += $(DRIVER_DEFINES) CFLAGS-cp/module.o += -DHOST_MACHINE=\"$(host)\" \ -DTARGET_MACHINE=\"$(target)\" +# In non-release builds, use a date-related module version. +ifneq ($(DEVPHASE_c),) +# Some date's don't grok 'r', if so, simply use today's +# date (don't bootstrap at midnight). +MODULE_VERSION := $(shell date -r $(srcdir)/cp/module.cc '+%y%m%d-%H%M' \ + 2>/dev/null || date '+%y%m%d-0000' 2>/dev/null || echo 0) + +CFLAGS-cp/module.o += -DMODULE_VERSION='($(subst -,,$(MODULE_VERSION))U)' +endif + # Create the compiler driver for g++. GXX_OBJS = $(GCC_OBJS) cp/g++spec.o xg++$(exeext): $(GXX_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) @@ -84,7 +94,8 @@ CXX_AND_OBJCXX_OBJS = \ cp/error.o cp/except.o cp/expr.o \ cp/friend.o cp/init.o \ cp/lambda.o cp/lex.o cp/logic.o \ - cp/mangle.o cp/method.o cp/module.o \ + cp/mangle.o cp/mapper-client.o cp/mapper-resolver.o \ + cp/method.o cp/module.o \ cp/name-lookup.o cp/optimize.o \ cp/parser.o cp/pt.o cp/ptree.o \ cp/rtti.o \ @@ -110,20 +121,21 @@ cp-warn = $(STRICT_WARN) # re-use the checksum from the prev-final stage so it passes # the bootstrap comparison and allows comparing of the cc1 binary cc1plus-checksum.c : build/genchecksum$(build_exeext) checksum-options \ - $(CXX_OBJS) $(BACKEND) $(LIBDEPS) + $(CXX_OBJS) $(BACKEND) $(CODYLIB) $(LIBDEPS) if [ -f ../stage_final ] \ && cmp -s ../stage_current ../stage_final; then \ cp ../prev-gcc/cc1plus-checksum.c cc1plus-checksum.c; \ else \ - build/genchecksum$(build_exeext) $(CXX_OBJS) $(BACKEND) $(LIBDEPS) \ + build/genchecksum$(build_exeext) $(CXX_OBJS) $(BACKEND) $(CODYLIB) $(LIBDEPS) \ checksum-options > cc1plus-checksum.c.tmp && \ $(srcdir)/../move-if-change cc1plus-checksum.c.tmp cc1plus-checksum.c; \ fi -cc1plus$(exeext): $(CXX_OBJS) cc1plus-checksum.o $(BACKEND) $(LIBDEPS) $(c++.prev) +cc1plus$(exeext): $(CXX_OBJS) cc1plus-checksum.o $(BACKEND) $(CODYLIB) $(LIBDEPS) $(c++.prev) @$(call LINK_PROGRESS,$(INDEX.c++),start) +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(CXX_OBJS) cc1plus-checksum.o $(BACKEND) $(LIBS) $(BACKENDLIBS) + $(CXX_OBJS) cc1plus-checksum.o $(BACKEND) $(CODYLIB) $(NETLIBS) \ + $(LIBS) $(BACKENDLIBS) @$(call LINK_PROGRESS,$(INDEX.c++),end) ifeq ($(ENABLE_MAINTAINER_RULES), true) diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f1e0bcb..87a7af1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1,5 +1,5 @@ /* Functions related to invoking -*- C++ -*- methods and overloaded functions. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) and modified by Brendan Kehoe (brendan@cygnus.com). @@ -761,12 +761,26 @@ alloc_conversions (size_t n) return (conversion **) conversion_obstack_alloc (n * sizeof (conversion *)); } +/* True iff the active member of conversion::u for code CODE is NEXT. */ + +static inline bool +has_next (conversion_kind code) +{ + return !(code == ck_identity + || code == ck_ambig + || code == ck_list + || code == ck_aggr); +} + static conversion * build_conv (conversion_kind code, tree type, conversion *from) { conversion *t; conversion_rank rank = CONVERSION_RANK (from); + /* Only call this function for conversions that use u.next. */ + gcc_assert (from == NULL || has_next (code)); + /* Note that the caller is responsible for filling in t->cand for user-defined conversions. */ t = alloc_conversion (code); @@ -863,10 +877,7 @@ static conversion * next_conversion (conversion *conv) { if (conv == NULL - || conv->kind == ck_identity - || conv->kind == ck_ambig - || conv->kind == ck_list - || conv->kind == ck_aggr) + || !has_next (conv->kind)) return NULL; return conv->u.next; } @@ -879,10 +890,7 @@ strip_standard_conversion (conversion *conv) { while (conv && conv->kind != ck_user - && conv->kind != ck_ambig - && conv->kind != ck_list - && conv->kind != ck_aggr - && conv->kind != ck_identity) + && has_next (conv->kind)) conv = next_conversion (conv); return conv; } @@ -1266,13 +1274,15 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, (TREE_TYPE (to), TREE_TYPE (from), NULL_TREE, c_cast_p, flags, complain); - if (part_conv) + if (!part_conv) + conv = NULL; + else if (part_conv->kind == ck_identity) + /* Leave conv alone. */; + else { conv = build_conv (part_conv->kind, to, conv); conv->rank = part_conv->rank; } - else - conv = NULL; return conv; } @@ -4025,9 +4035,9 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, creating a garbage BASELINK; constructors can't be inherited. */ ctors = get_class_binding (totype, complete_ctor_identifier); + tree to_nonref = non_reference (totype); if (MAYBE_CLASS_TYPE_P (fromtype)) { - tree to_nonref = non_reference (totype); if (same_type_ignoring_top_level_qualifiers_p (to_nonref, fromtype) || (CLASS_TYPE_P (to_nonref) && CLASS_TYPE_P (fromtype) && DERIVED_FROM_P (to_nonref, fromtype))) @@ -4111,6 +4121,22 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, tree conversion_path = TREE_PURPOSE (conv_fns); struct z_candidate *old_candidates; + /* If LOOKUP_NO_CONVERSION, don't consider a conversion function that + would need an addional user-defined conversion, i.e. if the return + type differs in class-ness from the desired type. So we avoid + considering operator bool when calling a copy constructor. + + This optimization avoids the failure in PR97600, and is allowed by + [temp.inst]/9: "If the function selected by overload resolution can be + determined without instantiating a class template definition, it is + unspecified whether that instantiation actually takes place." */ + tree convtype = non_reference (TREE_TYPE (conv_fns)); + if ((flags & LOOKUP_NO_CONVERSION) + && !WILDCARD_TYPE_P (convtype) + && (CLASS_TYPE_P (to_nonref) + != CLASS_TYPE_P (convtype))) + continue; + /* If we are called to convert to a reference type, we are trying to find a direct binding, so don't even consider temporaries. If we don't find a direct binding, the caller will try again to @@ -6357,6 +6383,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, print_z_candidates (loc, candidates); } result = error_mark_node; + if (overload) + *overload = error_mark_node; } else if (TREE_CODE (cand->fn) == FUNCTION_DECL) { @@ -7114,27 +7142,45 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, /* Issue diagnostics about a disallowed access of DECL, using DIAG_DECL in the diagnostics. - If ISSUE_ERROR is true, then issue an error about the - access, followed by a note showing the declaration. - Otherwise, just show the note. */ + If ISSUE_ERROR is true, then issue an error about the access, followed + by a note showing the declaration. Otherwise, just show the note. + + DIAG_DECL and DIAG_LOCATION will almost always be the same. + DIAG_LOCATION is just another DECL. NO_ACCESS_REASON is an optional + parameter used to specify why DECL wasn't accessible (e.g. ak_private + would be because DECL was private). If not using NO_ACCESS_REASON, + then it must be ak_none, and the access failure reason will be + figured out by looking at the protection of DECL. */ void -complain_about_access (tree decl, tree diag_decl, bool issue_error) +complain_about_access (tree decl, tree diag_decl, tree diag_location, + bool issue_error, access_kind no_access_reason) { - if (TREE_PRIVATE (decl)) + /* If we have not already figured out why DECL is inaccessible... */ + if (no_access_reason == ak_none) + { + /* Examine the access of DECL to find out why. */ + if (TREE_PRIVATE (decl)) + no_access_reason = ak_private; + else if (TREE_PROTECTED (decl)) + no_access_reason = ak_protected; + } + + /* Now generate an error message depending on calculated access. */ + if (no_access_reason == ak_private) { if (issue_error) error ("%q#D is private within this context", diag_decl); - inform (DECL_SOURCE_LOCATION (diag_decl), - "declared private here"); + inform (DECL_SOURCE_LOCATION (diag_location), "declared private here"); } - else if (TREE_PROTECTED (decl)) + else if (no_access_reason == ak_protected) { if (issue_error) error ("%q#D is protected within this context", diag_decl); - inform (DECL_SOURCE_LOCATION (diag_decl), - "declared protected here"); + inform (DECL_SOURCE_LOCATION (diag_location), "declared protected here"); } + /* Couldn't figure out why DECL is inaccesible, so just say it's + inaccessible. */ else { if (issue_error) @@ -8217,11 +8263,7 @@ type_passed_as (tree type) { /* Pass classes with copy ctors by invisible reference. */ if (TREE_ADDRESSABLE (type)) - { - type = build_reference_type (type); - /* There are no other pointers to this temporary. */ - type = cp_build_qualified_type (type, TYPE_QUAL_RESTRICT); - } + type = build_reference_type (type); else if (targetm.calls.promote_prototypes (NULL_TREE) && INTEGRAL_TYPE_P (type) && COMPLETE_TYPE_P (type) @@ -8397,17 +8439,75 @@ call_copy_ctor (tree a, tsubst_flags_t complain) return r; } -/* 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. +/* Return the base constructor corresponding to COMPLETE_CTOR or NULL_TREE. */ - 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. */ +static tree +base_ctor_for (tree complete_ctor) +{ + tree clone; + FOR_EACH_CLONE (clone, DECL_CLONED_FUNCTION (complete_ctor)) + if (DECL_BASE_CONSTRUCTOR_P (clone)) + return clone; + return NULL_TREE; +} -bool +/* Try to make EXP suitable to be used as the initializer for a base subobject, + and return whether we were successful. EXP must have already been cleared + by unsafe_copy_elision_p{,_opt}. */ + +static bool +make_base_init_ok (tree exp) +{ + if (TREE_CODE (exp) == TARGET_EXPR) + exp = TARGET_EXPR_INITIAL (exp); + while (TREE_CODE (exp) == COMPOUND_EXPR) + exp = TREE_OPERAND (exp, 1); + if (TREE_CODE (exp) == COND_EXPR) + { + bool ret = make_base_init_ok (TREE_OPERAND (exp, 2)); + if (tree op1 = TREE_OPERAND (exp, 1)) + { + bool r1 = make_base_init_ok (op1); + /* If unsafe_copy_elision_p was false, the arms should match. */ + gcc_assert (r1 == ret); + } + return ret; + } + if (TREE_CODE (exp) != AGGR_INIT_EXPR) + /* A trivial copy is OK. */ + return true; + if (!AGGR_INIT_VIA_CTOR_P (exp)) + /* unsafe_copy_elision_p_opt must have said this is OK. */ + return true; + tree fn = cp_get_callee_fndecl_nofold (exp); + if (DECL_BASE_CONSTRUCTOR_P (fn)) + return true; + gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (fn)); + fn = base_ctor_for (fn); + if (!fn || DECL_HAS_VTT_PARM_P (fn)) + /* The base constructor has more parameters, so we can't just change the + call target. It would be possible to splice in the appropriate + arguments, but probably not worth the complexity. */ + return false; + AGGR_INIT_EXPR_FN (exp) = build_address (fn); + return true; +} + +/* Return 2 if T refers to a base, 1 if a potentially-overlapping field, + neither of which can be used for return by invisible reference. We avoid + doing C++17 mandatory copy elision for either of these cases. + + This returns non-zero 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_opt does consider whether there is padding. */ + +int unsafe_return_slot_p (tree t) { + /* Check empty bases separately, they don't have fields. */ + if (is_empty_base_ref (t)) + return 2; + STRIP_NOPS (t); if (TREE_CODE (t) == ADDR_EXPR) t = TREE_OPERAND (t, 0); @@ -8418,28 +8518,21 @@ unsafe_return_slot_p (tree t) 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))); + if (DECL_FIELD_IS_BASE (t)) + return 2; + if (lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t))) + return 1; + return 0; } -/* 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. */ +/* True IFF EXP is a prvalue that represents return by invisible reference. */ static bool -unsafe_copy_elision_p (tree target, tree exp) +init_by_return_slot_p (tree exp) { /* Copy elision only happens with a TARGET_EXPR. */ if (TREE_CODE (exp) != TARGET_EXPR) 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 (!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 (!unsafe_return_slot_p (target)) - return false; tree init = TARGET_EXPR_INITIAL (exp); /* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR. */ while (TREE_CODE (init) == COMPOUND_EXPR) @@ -8447,16 +8540,58 @@ unsafe_copy_elision_p (tree target, tree exp) if (TREE_CODE (init) == COND_EXPR) { /* We'll end up copying from each of the arms of the COND_EXPR directly - into the target, so look at them. */ + into the target, so look at them. */ if (tree op = TREE_OPERAND (init, 1)) - if (unsafe_copy_elision_p (target, op)) + if (init_by_return_slot_p (op)) return true; - return unsafe_copy_elision_p (target, TREE_OPERAND (init, 2)); + return init_by_return_slot_p (TREE_OPERAND (init, 2)); } return (TREE_CODE (init) == AGGR_INIT_EXPR && !AGGR_INIT_VIA_CTOR_P (init)); } +/* 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. + + Places that use this function (or _opt) to decide to elide a copy should + probably use make_safe_copy_elision instead. */ + +static bool +unsafe_copy_elision_p (tree target, tree exp) +{ + return unsafe_return_slot_p (target) && init_by_return_slot_p (exp); +} + +/* As above, but for optimization allow more cases that are actually safe. */ + +static bool +unsafe_copy_elision_p_opt (tree target, tree exp) +{ + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); + /* It's safe to elide the copy for a class with no tail padding. */ + if (!is_empty_class (type) + && tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type))) + return false; + return unsafe_copy_elision_p (target, exp); +} + +/* Try to make EXP suitable to be used as the initializer for TARGET, + and return whether we were successful. */ + +bool +make_safe_copy_elision (tree target, tree exp) +{ + int uns = unsafe_return_slot_p (target); + if (!uns) + return true; + if (init_by_return_slot_p (exp)) + return false; + if (uns == 1) + return true; + return make_base_init_ok (exp); +} + /* True IFF the result of the conversion C is a prvalue. */ static bool @@ -9102,7 +9237,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) /* See unsafe_copy_elision_p. */ || unsafe_return_slot_p (fa)); - bool unsafe = unsafe_copy_elision_p (fa, arg); + bool unsafe = unsafe_copy_elision_p_opt (fa, arg); bool eliding_temp = (TREE_CODE (arg) == TARGET_EXPR && !unsafe); /* [class.copy]: the copy constructor is implicitly defined even if the @@ -9120,6 +9255,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) else cp_warn_deprecated_use (fn, complain); + if (eliding_temp && DECL_BASE_CONSTRUCTOR_P (fn) + && !make_base_init_ok (arg)) + unsafe = true; + /* If we're creating a temp and we already have one, don't create a new one. If we're not creating a temp but we get one, use INIT_EXPR to collapse the temp into our target. Otherwise, if the @@ -10438,6 +10577,8 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args, free (pretty_name); } call = error_mark_node; + if (fn_p) + *fn_p = error_mark_node; } else { @@ -10595,10 +10736,7 @@ is_subseq (conversion *ics1, conversion *ics2) ics2 = next_conversion (ics2); if (ics2->kind == ck_user - || ics2->kind == ck_ambig - || ics2->kind == ck_aggr - || ics2->kind == ck_list - || ics2->kind == ck_identity) + || !has_next (ics2->kind)) /* At this point, ICS1 cannot be a proper subsequence of ICS2. We can get a USER_CONV when we are comparing the second standard conversion sequence of two user conversion diff --git a/gcc/cp/cfns.gperf b/gcc/cp/cfns.gperf index 00eb841..729a981 100644 --- a/gcc/cp/cfns.gperf +++ b/gcc/cp/cfns.gperf @@ -2,7 +2,7 @@ %define class-name libc_name %struct-type %{ -/* Copyright (C) 2000-2020 Free Software Foundation, Inc. +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/cfns.h b/gcc/cp/cfns.h index 26d90c2..7f63918 100644 --- a/gcc/cp/cfns.h +++ b/gcc/cp/cfns.h @@ -30,7 +30,7 @@ #line 4 "cfns.gperf" -/* Copyright (C) 2000-2020 Free Software Foundation, Inc. +/* Copyright (C) 2000-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index ec47b06..40f5fef 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1,5 +1,5 @@ /* Functions related to building -*- C++ -*- classes and their related objects. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -494,8 +494,6 @@ build_base_path (enum tree_code code, if (want_pointer) target_type = ptr_target_type; - expr = build1 (NOP_EXPR, ptr_target_type, expr); - if (!integer_zerop (offset)) { offset = fold_convert (sizetype, offset); @@ -506,6 +504,8 @@ build_base_path (enum tree_code code, else null_test = NULL; + expr = build1 (NOP_EXPR, ptr_target_type, expr); + indout: if (!want_pointer) { @@ -659,6 +659,33 @@ convert_to_base_statically (tree expr, tree base) return expr; } +/* True IFF EXPR is a reference to an empty base class "subobject", as built in + convert_to_base_statically. We look for the result of the fold_convert + call, a NOP_EXPR from one pointer type to another, where the target is an + empty base of the original type. */ + +bool +is_empty_base_ref (tree expr) +{ + if (TREE_CODE (expr) == INDIRECT_REF) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) != NOP_EXPR) + return false; + tree type = TREE_TYPE (expr); + if (!POINTER_TYPE_P (type)) + return false; + type = TREE_TYPE (type); + if (!is_empty_class (type)) + return false; + STRIP_NOPS (expr); + tree fromtype = TREE_TYPE (expr); + if (!POINTER_TYPE_P (fromtype)) + return false; + fromtype = TREE_TYPE (fromtype); + return (CLASS_TYPE_P (fromtype) + && !same_type_ignoring_top_level_qualifiers_p (fromtype, type) + && DERIVED_FROM_P (type, fromtype)); +} tree build_vfield_ref (tree datum, tree type) @@ -1480,6 +1507,10 @@ mark_or_check_tags (tree t, tree *tp, abi_tag_data *p, bool val) static tree find_abi_tags_r (tree *tp, int *walk_subtrees, void *data) { + if (TYPE_P (*tp) && *walk_subtrees == 1) + /* Tell cp_walk_subtrees to look though typedefs. */ + *walk_subtrees = 2; + if (!OVERLOAD_TYPE_P (*tp)) return NULL_TREE; @@ -1500,6 +1531,10 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data) static tree mark_abi_tags_r (tree *tp, int *walk_subtrees, void *data) { + if (TYPE_P (*tp) && *walk_subtrees == 1) + /* Tell cp_walk_subtrees to look though typedefs. */ + *walk_subtrees = 2; + if (!OVERLOAD_TYPE_P (*tp)) return NULL_TREE; @@ -1800,15 +1835,13 @@ check_bases (tree t, else if (CLASSTYPE_REPEATED_BASE_P (t)) CLASSTYPE_NON_STD_LAYOUT (t) = 1; else - /* ...either has no non-static data members in the most-derived - class and at most one base class with non-static data - members, or has no base classes with non-static data - members. FIXME This was reworded in DR 1813. */ + /* ...has all non-static data members and bit-fields in the class + and its base classes first declared in the same class. */ for (basefield = TYPE_FIELDS (basetype); basefield; basefield = DECL_CHAIN (basefield)) if (TREE_CODE (basefield) == FIELD_DECL && !(DECL_FIELD_IS_BASE (basefield) - && integer_zerop (DECL_SIZE (basefield)))) + && is_empty_field (basefield))) { if (field) CLASSTYPE_NON_STD_LAYOUT (t) = 1; @@ -4191,6 +4224,25 @@ field_poverlapping_p (tree decl) DECL_ATTRIBUTES (decl)); } +/* Return true iff DECL is an empty field, either for an empty base or a + [[no_unique_address]] data member. */ + +bool +is_empty_field (tree decl) +{ + if (TREE_CODE (decl) != FIELD_DECL) + return false; + + bool r = (is_empty_class (TREE_TYPE (decl)) + && (DECL_FIELD_IS_BASE (decl) + || field_poverlapping_p (decl))); + + /* Empty fields should have size zero. */ + gcc_checking_assert (!r || integer_zerop (DECL_SIZE (decl))); + + return r; +} + /* Record all of the empty subobjects of DECL_OR_BINFO. */ static void @@ -4920,7 +4972,7 @@ build_clone (tree fn, tree name, bool need_vtt_parm_p, /* Build the clones of FN, return the number of clones built. These will be inserted onto DECL_CHAIN of FN. */ -static void +void build_cdtor_clones (tree fn, bool needs_vtt_p, bool base_omits_inherited_p, bool update_methods) { @@ -6577,7 +6629,9 @@ layout_class_type (tree t, tree *virtuals_p) /* end_of_class doesn't always give dsize, but it does in the case of a class with virtual bases, which is when dsize > nvsize. */ tree dsize = end_of_class (type, /*vbases*/true); - if (tree_int_cst_le (dsize, nvsize)) + if (CLASSTYPE_EMPTY_P (type)) + DECL_SIZE (field) = DECL_SIZE_UNIT (field) = size_zero_node; + else if (tree_int_cst_le (dsize, nvsize)) { DECL_SIZE_UNIT (field) = nvsize; DECL_SIZE (field) = CLASSTYPE_SIZE (type); @@ -6759,6 +6813,8 @@ layout_class_type (tree t, tree *virtuals_p) TYPE_CONTEXT (base_t) = t; DECL_CONTEXT (base_d) = t; + set_instantiating_module (base_d); + /* If the ABI version is not at least two, and the last field was a bit-field, RLI may not be on a byte boundary. In particular, rli_size_unit_so_far might @@ -8738,6 +8794,7 @@ build_self_reference (void) DECL_ARTIFICIAL (decl) = 1; SET_DECL_SELF_REFERENCE_P (decl); set_underlying_type (decl); + set_instantiating_module (decl); if (processing_template_decl) decl = push_template_decl (decl); diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in index da70b35..b5b2f28 100644 --- a/gcc/cp/config-lang.in +++ b/gcc/cp/config-lang.in @@ -1,5 +1,5 @@ # Top level configure fragment for GNU C++. -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. #This file is part of GCC. @@ -47,7 +47,7 @@ gtfiles="\ \$(srcdir)/cp/friend.c \ \$(srcdir)/cp/init.c \ \$(srcdir)/cp/lambda.c \$(srcdir)/cp/lex.c \$(srcdir)/cp/logic.cc \ -\$(srcdir)/cp/mangle.c \$(srcdir)/cp/method.c \ +\$(srcdir)/cp/mangle.c \$(srcdir)/cp/method.c \$(srcdir)/cp/module.cc \ \$(srcdir)/cp/name-lookup.c \ \$(srcdir)/cp/parser.c \$(srcdir)/cp/pt.c \ \$(srcdir)/cp/rtti.c \ diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index cb477c84..1dbc2db 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2,7 +2,7 @@ constexpr functions. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998-2020 Free Software Foundation, Inc. + Copyright (C) 1998-2021 Free Software Foundation, Inc. This file is part of GCC. @@ -821,7 +821,7 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain) /* A flexible array can't be intialized here, so don't complain that it isn't. */ continue; - if (DECL_SIZE (field) && integer_zerop (DECL_SIZE (field))) + if (is_empty_field (field)) /* An empty field doesn't need an initializer. */ continue; ftype = strip_array_types (ftype); @@ -1524,7 +1524,7 @@ unshare_constructor (tree t MEM_STAT_DECL) vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (n); constructor_elt *ce; for (HOST_WIDE_INT i = 0; vec_safe_iterate (v, i, &ce); ++i) - if (TREE_CODE (ce->value) == CONSTRUCTOR) + if (ce->value && TREE_CODE (ce->value) == CONSTRUCTOR) ptrs.safe_push (&ce->value); } return t; @@ -1591,6 +1591,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, if (TREE_ADDRESSABLE (type)) /* Undo convert_for_arg_passing work here. */ x = convert_from_reference (x); + /* Normally we would strip a TARGET_EXPR in an initialization context + such as this, but here we do the elision differently: we keep the + TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ arg = cxx_eval_constant_expression (ctx, x, /*lval=*/false, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ @@ -1998,11 +2001,20 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, to the object under construction or destruction, this object is considered to be a most derived object that has the type of the constructor or destructor's class. */ - tree vtable = build_vfield_ref (obj, TREE_TYPE (obj)); + tree vtable = build_vfield_ref (obj, objtype); vtable = cxx_eval_constant_expression (ctx, vtable, /*lval*/false, non_constant_p, overflow_p); if (*non_constant_p) return call; + /* With -fsanitize=vptr, we initialize all vtable pointers to null, + so it's possible that we got a null pointer now. */ + if (integer_zerop (vtable)) + { + if (!ctx->quiet) + error_at (loc, "virtual table pointer is used uninitialized"); + *non_constant_p = true; + return integer_zero_node; + } /* VTABLE will be &_ZTV1A + 16 or similar, get _ZTV1A. */ vtable = extract_obj_from_addr_offset (vtable); const tree mdtype = DECL_CONTEXT (vtable); @@ -2778,7 +2790,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, /* Rewrite all occurrences of the function's RESULT_DECL with the current object under construction. */ if (!*non_constant_p && ctx->object - && AGGREGATE_TYPE_P (TREE_TYPE (res)) + && CLASS_TYPE_P (TREE_TYPE (res)) && !is_empty_class (TREE_TYPE (res))) if (replace_result_decl (&result, res, ctx->object)) cacheable = false; @@ -3159,7 +3171,7 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, overflow_p); else if (code == SPACESHIP_EXPR) { - r = genericize_spaceship (type, lhs, rhs); + r = genericize_spaceship (loc, type, lhs, rhs); return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, overflow_p); } @@ -3462,7 +3474,9 @@ get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1) } else { - gcc_assert (TREE_CODE (index) == FIELD_DECL); + gcc_assert (TREE_CODE (index) == FIELD_DECL + && (same_type_ignoring_top_level_qualifiers_p + (DECL_CONTEXT (index), TREE_TYPE (ctor)))); /* We must keep the CONSTRUCTOR's ELTS in FIELD order. Usually we meet initializers in that order, but it is @@ -3746,6 +3760,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, tree empty_ctor = build_constructor (init_list_type_node, NULL); val = digest_init (elem_type, empty_ctor, tf_warning_or_error); new_ctx = *ctx; + new_ctx.object = t; new_ctx.ctor = build_constructor (elem_type, NULL); ctx = &new_ctx; } @@ -4539,7 +4554,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval, non_constant_p, overflow_p); } - if (*non_constant_p && !ctx->quiet) + if (*non_constant_p) break; if (new_ctx.ctor != ctx->ctor) { @@ -5265,7 +5280,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, }; CONSTRUCTOR_ELTS (ary_ctor)->quick_push (elt); } - + *valp = ary_ctor; } @@ -5277,6 +5292,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, type = refs->pop(); tree index = refs->pop(); + if (is_empty_field (index)) + /* Don't build a sub-CONSTRUCTOR for an empty base or field, as they + have no data and might have an offset lower than previously declared + fields, which confuses the middle-end. The code below will notice + that we don't have a CONSTRUCTOR for our inner target and just + return init. */ + break; + if (code == UNION_TYPE && CONSTRUCTOR_NELTS (*valp) && CONSTRUCTOR_ELT (*valp, 0)->index != index) { @@ -5379,6 +5402,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (!preeval) { + /* We're handling an INIT_EXPR of class type, so the value of the + initializer can depend on the object it's initializing. */ + /* Create a new CONSTRUCTOR in case evaluation of the initializer wants to modify it. */ if (*valp == NULL_TREE) @@ -6891,6 +6917,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; case BIT_CAST_EXPR: + if (lval) + { + if (!ctx->quiet) + error_at (EXPR_LOCATION (t), + "address of a call to %qs is not a constant expression", + "__builtin_bit_cast"); + *non_constant_p = true; + return t; + } r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p); break; @@ -7625,15 +7660,16 @@ check_automatic_or_tls (tree ref) struct check_for_return_continue_data { hash_set<tree> *pset; tree continue_stmt; + tree break_stmt; }; /* Helper function for potential_constant_expression_1 SWITCH_STMT handling, called through cp_walk_tree. Return the first RETURN_EXPR found, or note - the first CONTINUE_STMT if RETURN_EXPR is not found. */ + the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. */ static tree check_for_return_continue (tree *tp, int *walk_subtrees, void *data) { - tree t = *tp, s; + tree t = *tp, s, b; check_for_return_continue_data *d = (check_for_return_continue_data *) data; switch (TREE_CODE (t)) { @@ -7645,6 +7681,11 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data) d->continue_stmt = t; break; + case BREAK_STMT: + if (d->break_stmt == NULL_TREE) + d->break_stmt = t; + break; + #define RECUR(x) \ if (tree r = cp_walk_tree (&x, check_for_return_continue, data, \ d->pset)) \ @@ -7656,16 +7697,20 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; RECUR (DO_COND (t)); s = d->continue_stmt; + b = d->break_stmt; RECUR (DO_BODY (t)); d->continue_stmt = s; + d->break_stmt = b; break; case WHILE_STMT: *walk_subtrees = 0; RECUR (WHILE_COND (t)); s = d->continue_stmt; + b = d->break_stmt; RECUR (WHILE_BODY (t)); d->continue_stmt = s; + d->break_stmt = b; break; case FOR_STMT: @@ -7674,16 +7719,28 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data) RECUR (FOR_COND (t)); RECUR (FOR_EXPR (t)); s = d->continue_stmt; + b = d->break_stmt; RECUR (FOR_BODY (t)); d->continue_stmt = s; + d->break_stmt = b; break; case RANGE_FOR_STMT: *walk_subtrees = 0; RECUR (RANGE_FOR_EXPR (t)); s = d->continue_stmt; + b = d->break_stmt; RECUR (RANGE_FOR_BODY (t)); d->continue_stmt = s; + d->break_stmt = b; + break; + + case SWITCH_STMT: + *walk_subtrees = 0; + RECUR (SWITCH_STMT_COND (t)); + b = d->break_stmt; + RECUR (SWITCH_STMT_BODY (t)); + d->break_stmt = b; break; #undef RECUR @@ -8166,7 +8223,18 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, /* If we couldn't evaluate the condition, it might not ever be true. */ if (!integer_onep (tmp)) - return true; + { + /* Before returning true, check if the for body can contain + a return. */ + hash_set<tree> pset; + check_for_return_continue_data data = { &pset, NULL_TREE, + NULL_TREE }; + if (tree ret_expr + = cp_walk_tree (&FOR_BODY (t), check_for_return_continue, + &data, &pset)) + *jump_target = ret_expr; + return true; + } } if (!RECUR (FOR_EXPR (t), any)) return false; @@ -8195,7 +8263,18 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, tmp = cxx_eval_outermost_constant_expr (tmp, true); /* If we couldn't evaluate the condition, it might not ever be true. */ if (!integer_onep (tmp)) - return true; + { + /* Before returning true, check if the while body can contain + a return. */ + hash_set<tree> pset; + check_for_return_continue_data data = { &pset, NULL_TREE, + NULL_TREE }; + if (tree ret_expr + = cp_walk_tree (&WHILE_BODY (t), check_for_return_continue, + &data, &pset)) + *jump_target = ret_expr; + return true; + } if (!RECUR (WHILE_BODY (t), any)) return false; if (breaks (jump_target) || continues (jump_target)) @@ -8214,7 +8293,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, else { hash_set<tree> pset; - check_for_return_continue_data data = { &pset, NULL_TREE }; + check_for_return_continue_data data = { &pset, NULL_TREE, + NULL_TREE }; if (tree ret_expr = cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue, &data, &pset)) @@ -8624,11 +8704,46 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return RECUR (TREE_OPERAND (t, 2), want_rval); else if (TREE_CODE (tmp) == INTEGER_CST) return RECUR (TREE_OPERAND (t, 1), want_rval); + tmp = *jump_target; for (i = 1; i < 3; ++i) - if (potential_constant_expression_1 (TREE_OPERAND (t, i), - want_rval, strict, now, - tf_none, jump_target)) - return true; + { + tree this_jump_target = tmp; + if (potential_constant_expression_1 (TREE_OPERAND (t, i), + want_rval, strict, now, + tf_none, &this_jump_target)) + { + if (returns (&this_jump_target)) + *jump_target = this_jump_target; + else if (!returns (jump_target)) + { + if (breaks (&this_jump_target) + || continues (&this_jump_target)) + *jump_target = this_jump_target; + if (i == 1) + { + /* If the then branch is potentially constant, but + does not return, check if the else branch + couldn't return, break or continue. */ + hash_set<tree> pset; + check_for_return_continue_data data = { &pset, NULL_TREE, + NULL_TREE }; + if (tree ret_expr + = cp_walk_tree (&TREE_OPERAND (t, 2), + check_for_return_continue, &data, + &pset)) + *jump_target = ret_expr; + else if (*jump_target == NULL_TREE) + { + if (data.continue_stmt) + *jump_target = data.continue_stmt; + else if (data.break_stmt) + *jump_target = data.break_stmt; + } + } + } + return true; + } + } if (flags & tf_error) error_at (loc, "expression %qE is not a constant expression", t); return false; diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index b4c501b..9049d08 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1,5 +1,5 @@ /* Processing rules for constraints. - Copyright (C) 2013-2020 Free Software Foundation, Inc. + Copyright (C) 2013-2021 Free Software Foundation, Inc. Contributed by Andrew Sutton (andrew.n.sutton@gmail.com) This file is part of GCC. @@ -2374,35 +2374,110 @@ tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_ Constraint satisfaction ---------------------------------------------------------------------------*/ -/* Hash functions for satisfaction entries. */ +/* True if we are currently satisfying a constraint. */ + +static bool satisfying_constraint; + +/* A vector of incomplete types (and of declarations with undeduced return type), + appended to by note_failed_type_completion_for_satisfaction. The + satisfaction caches use this in order to keep track of "potentially unstable" + satisfaction results. + + Since references to entries in this vector are stored only in the + GC-deletable sat_cache, it's safe to make this deletable as well. */ + +static GTY((deletable)) vec<tree, va_gc> *failed_type_completions; + +/* Called whenever a type completion (or return type deduction) failure occurs + that definitely affects the meaning of the program, by e.g. inducing + substitution failure. */ + +void +note_failed_type_completion_for_satisfaction (tree t) +{ + if (satisfying_constraint) + { + gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t)) + || (DECL_P (t) && undeduced_auto_decl (t))); + vec_safe_push (failed_type_completions, t); + } +} + +/* Returns true if the range [BEGIN, END) of elements within the + failed_type_completions vector contains a complete type (or a + declaration with a non-placeholder return type). */ + +static bool +some_type_complete_p (int begin, int end) +{ + for (int i = begin; i < end; i++) + { + tree t = (*failed_type_completions)[i]; + if (TYPE_P (t) && COMPLETE_TYPE_P (t)) + return true; + if (DECL_P (t) && !undeduced_auto_decl (t)) + return true; + } + return false; +} + +/* Hash functions and data types for satisfaction cache entries. */ struct GTY((for_user)) sat_entry { - tree constr; + /* The relevant ATOMIC_CONSTR. */ + tree atom; + + /* The relevant template arguments. */ tree args; + + /* The result of satisfaction of ATOM+ARGS. + This is either boolean_true_node, boolean_false_node or error_mark_node, + where error_mark_node indicates ill-formed satisfaction. + It's set to NULL_TREE while computing satisfaction of ATOM+ARGS for + the first time. */ tree result; + + /* The value of input_location when satisfaction of ATOM+ARGS was first + performed. */ + location_t location; + + /* The range of elements appended to the failed_type_completions vector + during computation of this satisfaction result, encoded as a begin/end + pair of offsets. */ + int ftc_begin, ftc_end; + + /* True if we want to diagnose the above instability when it's detected. + We don't always want to do so, in order to avoid emitting duplicate + diagnostics in some cases. */ + bool diagnose_instability; + + /* True if we're in the middle of computing this satisfaction result. + Used during both quiet and noisy satisfaction to detect self-recursive + satisfaction. */ + bool evaluating; }; struct sat_hasher : ggc_ptr_hash<sat_entry> { static hashval_t hash (sat_entry *e) { - if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e->constr)) + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e->atom)) { /* Atoms with instantiated mappings are built during satisfaction. They live only inside the sat_cache, and we build one to query the cache with each time we instantiate a mapping. */ gcc_assert (!e->args); - return hash_atomic_constraint (e->constr); + return hash_atomic_constraint (e->atom); } /* Atoms with uninstantiated mappings are built during normalization. Since normalize_atom caches the atoms it returns, we can assume pointer-based identity for fast hashing and comparison. Even if this assumption is violated, that's okay, we'll just get a cache miss. */ - hashval_t value = htab_hash_pointer (e->constr); + hashval_t value = htab_hash_pointer (e->atom); - if (tree map = ATOMIC_CONSTR_MAP (e->constr)) + if (tree map = ATOMIC_CONSTR_MAP (e->atom)) /* Only the parameters that are used in the targets of the mapping affect the satisfaction value of the atom. So we consider only the arguments for these parameters, and ignore the rest. */ @@ -2421,21 +2496,21 @@ struct sat_hasher : ggc_ptr_hash<sat_entry> static bool equal (sat_entry *e1, sat_entry *e2) { - if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->constr) - != ATOMIC_CONSTR_MAP_INSTANTIATED_P (e2->constr)) + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->atom) + != ATOMIC_CONSTR_MAP_INSTANTIATED_P (e2->atom)) return false; /* See sat_hasher::hash. */ - if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->constr)) + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->atom)) { gcc_assert (!e1->args && !e2->args); - return atomic_constraints_identical_p (e1->constr, e2->constr); + return atomic_constraints_identical_p (e1->atom, e2->atom); } - if (e1->constr != e2->constr) + if (e1->atom != e2->atom) return false; - if (tree map = ATOMIC_CONSTR_MAP (e1->constr)) + if (tree map = ATOMIC_CONSTR_MAP (e1->atom)) for (tree target_parms = TREE_TYPE (map); target_parms; target_parms = TREE_CHAIN (target_parms)) @@ -2458,73 +2533,168 @@ static GTY((deletable)) hash_table<sat_hasher> *sat_cache; /* Cache the result of constraint_satisfaction_value. */ static GTY((deletable)) hash_map<tree, tree> *decl_satisfied_cache; -static tree -get_satisfaction (tree constr, tree args) +/* A tool used by satisfy_atom to help manage satisfaction caching and to + diagnose "unstable" satisfaction values. We insert into the cache only + when performing satisfaction quietly. */ + +struct satisfaction_cache { - if (!sat_cache) - return NULL_TREE; - sat_entry elt = { constr, args, NULL_TREE }; - sat_entry* found = sat_cache->find (&elt); - if (found) - return found->result; - else - return NULL_TREE; -} + satisfaction_cache (tree, tree, sat_info); + tree get (); + tree save (tree); -static void -save_satisfaction (tree constr, tree args, tree result) + sat_entry *entry; + sat_info info; + int ftc_begin; +}; + +/* Constructor for the satisfaction_cache class. We're performing satisfaction + of ATOM+ARGS according to INFO. */ + +satisfaction_cache +::satisfaction_cache (tree atom, tree args, sat_info info) + : entry(nullptr), info(info), ftc_begin(-1) { if (!sat_cache) sat_cache = hash_table<sat_hasher>::create_ggc (31); - sat_entry elt = {constr, args, result}; - sat_entry** slot = sat_cache->find_slot (&elt, INSERT); - sat_entry* entry = ggc_alloc<sat_entry> (); - *entry = elt; - *slot = entry; + + /* When noisy, we query the satisfaction cache in order to diagnose + "unstable" satisfaction values. */ + if (info.noisy ()) + { + /* When noisy, constraints have been re-normalized, and that breaks the + pointer-based identity assumption of sat_cache (for atoms with + uninstantiated mappings). So undo this re-normalization by looking in + the atom_cache for the corresponding atom that was used during quiet + satisfaction. */ + if (!ATOMIC_CONSTR_MAP_INSTANTIATED_P (atom)) + { + if (tree found = atom_cache->find (atom)) + atom = found; + else + /* The lookup should always succeed, but if it fails then let's + just leave 'entry' empty, effectively disabling the cache. */ + return; + } + } + + /* Look up or create the corresponding satisfaction entry. */ + sat_entry elt; + elt.atom = atom; + elt.args = args; + sat_entry **slot = sat_cache->find_slot (&elt, INSERT); + if (*slot) + entry = *slot; + else if (info.quiet ()) + { + entry = ggc_alloc<sat_entry> (); + entry->atom = atom; + entry->args = args; + entry->result = NULL_TREE; + entry->location = input_location; + entry->ftc_begin = entry->ftc_end = -1; + entry->diagnose_instability = false; + if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (atom)) + /* We always want to diagnose instability of an atom with an + instantiated parameter mapping. For atoms with an uninstantiated + mapping, we set this flag (in satisfy_atom) only if substitution + into its mapping previously failed. */ + entry->diagnose_instability = true; + entry->evaluating = false; + *slot = entry; + } + else + /* We shouldn't get here, but if we do, let's just leave 'entry' + empty, effectively disabling the cache. */ + return; } -/* A tool to help manage satisfaction caching in satisfy_constraint_r. - Note the cache is only used when not diagnosing errors. */ +/* Returns the cached satisfaction result if we have one and we're not + recomputing the satisfaction result from scratch. Otherwise returns + NULL_TREE. */ -struct satisfaction_cache +tree +satisfaction_cache::get () { - satisfaction_cache (tree constr, tree args, tsubst_flags_t complain) - : constr(constr), args(args), complain(complain) - { } - - tree get () - { - if (complain == tf_none) - return get_satisfaction (constr, args); + if (!entry) return NULL_TREE; - } - tree save (tree result) - { - if (complain == tf_none) - save_satisfaction (constr, args, result); - return result; - } + if (entry->evaluating) + { + /* If we get here, it means satisfaction is self-recursive. */ + gcc_checking_assert (!entry->result); + if (info.noisy ()) + error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (entry->atom)), + "satisfaction of atomic constraint %qE depends on itself", + entry->atom); + return error_mark_node; + } - tree constr; - tree args; - tsubst_flags_t complain; -}; + /* This satisfaction result is "potentially unstable" if a type for which + type completion failed during its earlier computation is now complete. */ + bool maybe_unstable = some_type_complete_p (entry->ftc_begin, + entry->ftc_end); -static int satisfying_constraint = 0; + if (info.noisy () || maybe_unstable || !entry->result) + { + /* We're computing the satisfaction result from scratch. */ + entry->evaluating = true; + ftc_begin = vec_safe_length (failed_type_completions); + return NULL_TREE; + } + else + return entry->result; +} -/* Returns true if we are currently satisfying a constraint. +/* RESULT is the computed satisfaction result. If RESULT differs from the + previously cached result, this routine issues an appropriate error. + Otherwise, when evaluating quietly, updates the cache appropriately. */ - This is used to guard against recursive calls to evaluate_concept_check - during template argument substitution. +tree +satisfaction_cache::save (tree result) +{ + if (!entry) + return result; - TODO: Do we need this now that we fully normalize prior to evaluation? - I think not. */ + gcc_checking_assert (entry->evaluating); + entry->evaluating = false; -bool -satisfying_constraint_p () -{ - return satisfying_constraint; + if (entry->result && result != entry->result) + { + if (info.quiet ()) + /* Return error_mark_node to force satisfaction to get replayed + noisily. */ + return error_mark_node; + else + { + if (entry->diagnose_instability) + { + auto_diagnostic_group d; + error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (entry->atom)), + "satisfaction value of atomic constraint %qE changed " + "from %qE to %qE", entry->atom, entry->result, result); + inform (entry->location, + "satisfaction value first evaluated to %qE from here", + entry->result); + } + /* For sake of error recovery, allow this latest satisfaction result + to prevail. */ + entry->result = result; + return result; + } + } + + if (info.quiet ()) + { + entry->result = result; + /* Store into this entry the list of relevant failed type completions + that occurred during (re)computation of the satisfaction result. */ + gcc_checking_assert (ftc_begin != -1); + entry->ftc_begin = ftc_begin; + entry->ftc_end = vec_safe_length (failed_type_completions); + } + + return result; } /* Substitute ARGS into constraint-expression T during instantiation of @@ -2722,18 +2892,18 @@ static void diagnose_atomic_constraint (tree, tree, tree, subst_info); static tree satisfy_atom (tree t, tree args, sat_info info) { - satisfaction_cache cache (t, args, info.complain); + /* In case there is a diagnostic, we want to establish the context + prior to printing errors. If no errors occur, this context is + removed before returning. */ + diagnosing_failed_constraint failure (t, args, info.noisy ()); + + satisfaction_cache cache (t, args, info); if (tree r = cache.get ()) return r; /* Perform substitution quietly. */ subst_info quiet (tf_none, NULL_TREE); - /* In case there is a diagnostic, we want to establish the context - prior to printing errors. If no errors occur, this context is - removed before returning. */ - diagnosing_failed_constraint failure (t, args, info.noisy ()); - /* Instantiate the parameter mapping. */ tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet); if (map == error_mark_node) @@ -2742,6 +2912,11 @@ satisfy_atom (tree t, tree args, sat_info info) not satisfied. Replay the substitution. */ if (info.diagnose_unsatisfaction_p ()) tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, info); + if (info.quiet ()) + /* Since instantiation of the parameter mapping failed, we + want to diagnose potential instability of this satisfaction + result. */ + cache.entry->diagnose_instability = true; return cache.save (boolean_false_node); } @@ -2753,9 +2928,12 @@ satisfy_atom (tree t, tree args, sat_info info) ATOMIC_CONSTR_MAP (t) = map; gcc_assert (!ATOMIC_CONSTR_MAP_INSTANTIATED_P (t)); ATOMIC_CONSTR_MAP_INSTANTIATED_P (t) = true; - satisfaction_cache inst_cache (t, /*args=*/NULL_TREE, info.complain); + satisfaction_cache inst_cache (t, /*args=*/NULL_TREE, info); if (tree r = inst_cache.get ()) - return cache.save (r); + { + cache.entry->location = inst_cache.entry->location; + return cache.save (r); + } /* Rebuild the argument vector from the parameter mapping. */ args = get_mapped_args (map); @@ -2838,6 +3016,8 @@ satisfy_constraint (tree t, tree args, sat_info info) { auto_timevar time (TV_CONSTRAINT_SAT); + auto ovr = make_temp_override (satisfying_constraint, true); + /* Turn off template processing. Constraint satisfaction only applies to non-dependent terms, so we want to ensure full checking here. */ processing_template_decl_sentinel proc (true); @@ -2946,6 +3126,8 @@ satisfy_declaration_constraints (tree t, sat_info info) norm = normalize_nontemplate_requirements (t, info.noisy ()); } + unsigned ftc_count = vec_safe_length (failed_type_completions); + tree result = boolean_true_node; if (norm) { @@ -2957,7 +3139,19 @@ satisfy_declaration_constraints (tree t, sat_info info) pop_tinst_level (); } - if (info.quiet ()) + /* True if this satisfaction is (heuristically) potentially unstable, i.e. + if its result may depend on where in the program it was performed. */ + bool maybe_unstable_satisfaction = false; + if (ftc_count != vec_safe_length (failed_type_completions)) + /* Type completion failure occurred during satisfaction. The satisfaction + result may (or may not) materially depend on the completeness of a type, + so we consider it potentially unstable. */ + maybe_unstable_satisfaction = true; + + if (maybe_unstable_satisfaction) + /* Don't cache potentially unstable satisfaction, to allow satisfy_atom + to check the stability the next time around. */; + else if (info.quiet ()) hash_map_safe_put<hm_ggc> (decl_satisfied_cache, saved_t, result); return result; diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index fd6cda4..e61de1f 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1,6 +1,6 @@ /* coroutine-specific state, expansions and tests. - Copyright (C) 2018-2020 Free Software Foundation, Inc. + Copyright (C) 2018-2021 Free Software Foundation, Inc. Contributed by Iain Sandoe <iain@sandoe.co.uk> under contract to Facebook. diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 8bbcf01..4d0e92c 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -1,6 +1,6 @@ /* C++-specific tree lowering bits; see also c-gimplify.c and gimple.c. - Copyright (C) 2002-2020 Free Software Foundation, Inc. + Copyright (C) 2002-2021 Free Software Foundation, Inc. Contributed by Jason Merrill <jason@redhat.com> This file is part of GCC. @@ -882,7 +882,7 @@ static tree genericize_spaceship (tree expr) tree type = TREE_TYPE (expr); tree op0 = TREE_OPERAND (expr, 0); tree op1 = TREE_OPERAND (expr, 1); - return genericize_spaceship (type, op0, op1); + return genericize_spaceship (input_location, type, op0, op1); } /* If EXPR involves an anonymous VLA type, prepend a DECL_EXPR for that type @@ -2931,6 +2931,21 @@ struct source_location_table_entry_hash && ref.uid == 0 && ref.var == NULL_TREE); } + + static void + pch_nx (source_location_table_entry &p) + { + extern void gt_pch_nx (source_location_table_entry &); + gt_pch_nx (p); + } + + static void + pch_nx (source_location_table_entry &p, gt_pointer_operator op, void *cookie) + { + extern void gt_pch_nx (source_location_table_entry *, gt_pointer_operator, + void *); + gt_pch_nx (&p, op, cookie); + } }; static GTY(()) hash_table <source_location_table_entry_hash> diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 9e980bc..081b834 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -1,5 +1,5 @@ /* Language-dependent hooks for C++. - Copyright (C) 2001-2020 Free Software Foundation, Inc. + Copyright (C) 2001-2021 Free Software Foundation, Inc. Contributed by Alexandre Oliva <aoliva@redhat.com> This file is part of GCC. @@ -34,6 +34,8 @@ static tree cp_eh_personality (void); static tree get_template_innermost_arguments_folded (const_tree); static tree get_template_argument_pack_elems_folded (const_tree); static tree cxx_enum_underlying_base_type (const_tree); +static tree *cxx_omp_get_decl_init (tree); +static void cxx_omp_finish_decl_inits (void); /* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h; consequently, there should be very few hooks below. */ @@ -77,6 +79,12 @@ static tree cxx_enum_underlying_base_type (const_tree); #define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type #undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE #define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE cxx_enum_underlying_base_type +#undef LANG_HOOKS_PREPROCESS_MAIN_FILE +#define LANG_HOOKS_PREPROCESS_MAIN_FILE module_begin_main_file +#undef LANG_HOOKS_PREPROCESS_OPTIONS +#define LANG_HOOKS_PREPROCESS_OPTIONS module_preprocess_options +#undef LANG_HOOKS_PREPROCESS_TOKEN +#define LANG_HOOKS_PREPROCESS_TOKEN module_token_pre #if CHECKING_P #undef LANG_HOOKS_RUN_LANG_SELFTESTS @@ -86,6 +94,12 @@ static tree cxx_enum_underlying_base_type (const_tree); #undef LANG_HOOKS_GET_SUBSTRING_LOCATION #define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location +#undef LANG_HOOKS_OMP_GET_DECL_INIT +#define LANG_HOOKS_OMP_GET_DECL_INIT cxx_omp_get_decl_init + +#undef LANG_HOOKS_OMP_FINISH_DECL_INITS +#define LANG_HOOKS_OMP_FINISH_DECL_INITS cxx_omp_finish_decl_inits + /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; @@ -227,6 +241,30 @@ tree cxx_enum_underlying_base_type (const_tree type) return underlying_type; } +/* The C++ version of the omp_get_decl_init langhook returns the static + initializer for a variable declaration if present, otherwise it + tries to find and return the dynamic initializer. If not present, + it returns NULL. */ + +static tree * +cxx_omp_get_decl_init (tree decl) +{ + if (DECL_INITIAL (decl)) + return &DECL_INITIAL (decl); + + return hash_map_safe_get (dynamic_initializers, decl); +} + +/* The C++ version of the omp_finish_decl_inits langhook allows GC to + reclaim the memory used by the hash-map used to hold dynamic initializer + information. */ + +static void +cxx_omp_finish_decl_inits (void) +{ + dynamic_initializers = NULL; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/cp/cp-name-hint.h b/gcc/cp/cp-name-hint.h index f373e5f..2fe89ed 100644 --- a/gcc/cp/cp-name-hint.h +++ b/gcc/cp/cp-name-hint.h @@ -1,5 +1,5 @@ /* Declarations for working with name_hint instances in the C++ frontend. - Copyright (C) 2018-2020 Free Software Foundation, Inc. + Copyright (C) 2018-2021 Free Software Foundation, Inc. Contributed by David Malcolm <dmalcolm@redhat.com> This file is part of GCC. diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 7ff4d39..9847270 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -1,5 +1,5 @@ /* Some code common to C++ and ObjC++ front ends. - Copyright (C) 2004-2020 Free Software Foundation, Inc. + Copyright (C) 2004-2021 Free Software Foundation, Inc. Contributed by Ziemowit Laski <zlaski@apple.com> This file is part of GCC. @@ -438,6 +438,9 @@ cp_register_dumps (gcc::dump_manager *dumps) class_dump_id = dumps->dump_register (".class", "lang-class", "lang-class", DK_lang, OPTGROUP_NONE, false); + module_dump_id = dumps->dump_register + (".module", "lang-module", "lang-module", DK_lang, OPTGROUP_NONE, false); + raw_dump_id = dumps->dump_register (".raw", "lang-raw", "lang-raw", DK_lang, OPTGROUP_NONE, false); } @@ -551,4 +554,16 @@ cp_common_init_ts (void) c_common_init_ts (); } +/* Handle C++-specficic options here. Punt to c_common otherwise. */ + +bool +cp_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, + int kind, location_t loc, + const struct cl_option_handlers *handlers) +{ + if (handle_module_option (unsigned (scode), arg, value)) + return true; + return c_common_handle_option (scode, arg, value, kind, loc, handlers); +} + #include "gt-cp-cp-objcp-common.h" diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 0936f16..53c6e4c 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -1,5 +1,5 @@ /* Language hooks common to C++ and ObjC++ front ends. - Copyright (C) 2004-2020 Free Software Foundation, Inc. + Copyright (C) 2004-2021 Free Software Foundation, Inc. Contributed by Ziemowit Laski <zlaski@apple.com> This file is part of GCC. @@ -34,6 +34,8 @@ extern tree cp_unit_size_without_reusable_padding (tree); extern tree cp_get_global_decls (); extern tree cp_pushdecl (tree); extern void cp_register_dumps (gcc::dump_manager *); +extern bool cp_handle_option (size_t, const char *, HOST_WIDE_INT, int, + location_t, const struct cl_option_handlers *); extern tree cxx_make_type_hook (tree_code); extern tree cxx_simulate_enum_decl (location_t, const char *, vec<string_int_pair>); @@ -63,7 +65,7 @@ extern tree cxx_simulate_enum_decl (location_t, const char *, #undef LANG_HOOKS_REGISTER_DUMPS #define LANG_HOOKS_REGISTER_DUMPS cp_register_dumps #undef LANG_HOOKS_HANDLE_OPTION -#define LANG_HOOKS_HANDLE_OPTION c_common_handle_option +#define LANG_HOOKS_HANDLE_OPTION cp_handle_option #undef LANG_HOOKS_HANDLE_FILENAME #define LANG_HOOKS_HANDLE_FILENAME c_common_handle_filename #undef LANG_HOOKS_POST_OPTIONS diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index c58b233..725139b 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -1,7 +1,7 @@ /* This file contains the definitions and documentation for the additional tree codes used in the GNU C++ compiler (see tree.def for the standard codes). - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b72069e..aed85d7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1,5 +1,5 @@ /* Definitions for -*- C++ -*- parsing and type checking. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -1932,6 +1932,38 @@ public: ~temp_override() { overridden_variable = saved_value; } }; +/* Wrapping a template parameter in type_identity_t hides it from template + argument deduction. */ +#if __cpp_lib_type_identity +using std::type_identity_t; +#else +template <typename T> +struct type_identity { typedef T type; }; +template <typename T> +using type_identity_t = typename type_identity<T>::type; +#endif + +/* Object generator function for temp_override, so you don't need to write the + type of the object as a template argument. + + Use as auto x = make_temp_override (flag); */ + +template <typename T> +inline temp_override<T> +make_temp_override (T& var) +{ + return { var }; +} + +/* Likewise, but use as auto x = make_temp_override (flag, value); */ + +template <typename T> +inline temp_override<T> +make_temp_override (T& var, type_identity_t<T> overrider) +{ + return { var, overrider }; +} + /* The cached class binding level, from the most recently exited class, or NULL if none. */ @@ -5417,11 +5449,18 @@ 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 and alias specializations - in structrual_comptypes. */ +/* Nonzero if we are inside spec_hasher::equal, which affects + comparison of PARM_DECLs in cp_tree_equal. */ extern int comparing_specializations; +/* Nonzero if we want different dependent aliases to compare as unequal. + FIXME we should always do this except during deduction/ordering. */ +extern int comparing_dependent_aliases; + +/* When comparing specializations permit context _FROM to match _TO. */ +extern tree map_context_from; +extern tree map_context_to; + /* In parser.c. */ /* Nonzero if we are parsing an unevaluated operand: an operand to @@ -5595,6 +5634,10 @@ extern GTY(()) tree static_aggregates; /* Likewise, for thread local storage. */ extern GTY(()) tree tls_aggregates; +/* A hash-map mapping from variable decls to the dynamic initializer for + the decl. This is currently only used by OpenMP. */ +extern GTY(()) decl_tree_map *dynamic_initializers; + enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; /* These are uses as bits in flags passed to various functions to @@ -6196,6 +6239,13 @@ struct GTY((chain_next ("%h.next"))) tinst_level { arguments. */ tree tldcl, targs; + /* For modules we need to know (a) the modules on the path of + instantiation and (b) the transitive imports along that path. + Note that these two bitmaps may be inherited from NEXT, if this + decl is in the same module as NEXT (or has no new information). */ + bitmap path; + bitmap visible; + private: /* Return TRUE iff the original node is a split list. */ bool split_list_p () const { return targs; } @@ -6291,6 +6341,7 @@ extern cp_parameter_declarator *no_parameters; /* Various dump ids. */ extern int class_dump_id; +extern int module_dump_id; extern int raw_dump_id; /* in call.c */ @@ -6328,6 +6379,13 @@ extern tree build_new_op (const op_location_t &, enum tree_code, int, tree, tree, tree, tree *, tsubst_flags_t); +/* Wrapper that leaves out the usually-null op3 and overload parms. */ +inline tree build_new_op (const op_location_t &loc, enum tree_code code, + int flags, tree arg1, tree arg2, + tsubst_flags_t complain) +{ + return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL, complain); +} extern tree build_op_call (tree, vec<tree, va_gc> **, tsubst_flags_t); extern bool aligned_allocation_fn_p (tree); @@ -6379,7 +6437,8 @@ class access_failure_info tree m_diag_decl; }; -extern void complain_about_access (tree, tree, bool); +extern void complain_about_access (tree, tree, tree, bool, + access_kind); extern void push_defarg_context (tree); extern void pop_defarg_context (void); extern tree convert_default_arg (tree, tree, tree, int, @@ -6416,7 +6475,8 @@ 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 int unsafe_return_slot_p (tree); +extern bool make_safe_copy_elision (tree, 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); @@ -6429,6 +6489,7 @@ extern tree build_base_path (enum tree_code, tree, extern tree convert_to_base (tree, tree, bool, bool, tsubst_flags_t); extern tree convert_to_base_statically (tree, tree); +extern bool is_empty_base_ref (tree); extern tree build_vtbl_ref (tree, tree); extern tree build_vfn_ref (tree, tree); extern tree get_vtable_decl (tree, int); @@ -6457,6 +6518,7 @@ extern int same_signature_p (const_tree, const_tree); extern tree lookup_vfn_in_binfo (tree, tree); extern void maybe_add_class_template_decl_list (tree, tree, int); extern void unreverse_member_declarations (tree); +extern bool is_empty_field (tree); extern void invalidate_class_lookup_cache (void); extern void maybe_note_name_used_in_class (tree, tree); extern void note_name_declared_in_class (tree, tree); @@ -6497,6 +6559,7 @@ extern void check_abi_tags (tree); extern tree missing_abi_tags (tree); extern void fixup_type_variants (tree); extern void fixup_attribute_variants (tree); +extern void build_cdtor_clones (tree, bool, bool, bool); extern void clone_cdtor (tree, bool); extern tree copy_operator_fn (tree, tree_code code); extern void adjust_clone_args (tree); @@ -6849,6 +6912,10 @@ extern void set_identifier_kind (tree, cp_identifier_kind); extern bool cxx_init (void); extern void cxx_finish (void); extern bool in_main_input_context (void); +extern uintptr_t module_token_pre (cpp_reader *, const cpp_token *, uintptr_t); +extern uintptr_t module_token_cdtor (cpp_reader *, uintptr_t); +extern uintptr_t module_token_lang (int type, int keyword, tree value, + location_t, uintptr_t); /* in method.c */ extern void init_method (void); @@ -6974,7 +7041,7 @@ extern void maybe_check_all_macros (cpp_reader *); extern void finish_module_processing (cpp_reader *); extern char const *module_name (unsigned, bool header_ok); extern bitmap get_import_bitmap (); -extern bitmap module_visible_instantiation_path (bitmap *); +extern bitmap visible_instantiation_path (bitmap *); extern void module_begin_main_file (cpp_reader *, line_maps *, const line_map_ordinary *); extern void module_preprocess_options (cpp_reader *); @@ -7185,8 +7252,8 @@ extern void walk_specializations (bool, void (*)(bool, spec_entry *, void *), void *); -extern tree match_mergeable_specialization (bool is_decl, tree tmpl, - tree args, tree spec); +extern tree match_mergeable_specialization (bool is_decl, spec_entry *, + bool insert = true); extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec); extern void add_mergeable_specialization (tree tmpl, tree args, tree spec, unsigned); @@ -7212,6 +7279,7 @@ extern unsigned get_pseudo_tinfo_index (tree); extern tree get_pseudo_tinfo_type (unsigned); /* in search.c */ +extern tree get_parent_with_private_access (tree decl, tree binfo); extern bool accessible_base_p (tree, tree, bool); extern tree lookup_base (tree, tree, base_access, base_kind *, tsubst_flags_t); @@ -7250,7 +7318,7 @@ extern tree adjust_result_of_qualified_name_lookup (tree, tree, tree); extern tree copied_binfo (tree, tree); extern tree original_binfo (tree, tree); -extern int shared_member_p (tree); +extern bool shared_member_p (tree); extern bool any_dependent_bases_p (tree = current_nonlambda_class_type ()); extern bool maybe_check_overriding_exception_spec (tree, tree); @@ -7570,7 +7638,7 @@ extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); extern tree build_qualified_name (tree, tree, tree, bool); extern tree build_ref_qualified_type (tree, cp_ref_qualifier); -extern tree make_binding_vec (tree, unsigned clusters); +extern tree make_binding_vec (tree, unsigned clusters CXX_MEM_STAT_INFO); inline tree ovl_first (tree) ATTRIBUTE_PURE; extern tree ovl_make (tree fn, tree next = NULL_TREE); @@ -7795,7 +7863,7 @@ extern tree merge_types (tree, tree); extern tree strip_array_domain (tree); extern tree check_return_expr (tree, bool *); extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error); -extern tree genericize_spaceship (tree, tree, tree); +extern tree genericize_spaceship (location_t, tree, tree, tree); extern tree cp_build_binary_op (const op_location_t &, enum tree_code, tree, tree, tsubst_flags_t); @@ -7912,6 +7980,9 @@ extern tree mangle_template_parm_object (tree); extern char *get_mangled_vtable_map_var_name (tree); extern bool mangle_return_type_p (tree); extern tree mangle_decomp (tree, vec<tree> &); +extern void mangle_module_substitution (int); +extern void mangle_identifier (char, tree); +extern tree mangle_module_global_init (int); /* in dump.c */ extern bool cp_dump_tree (void *, tree); @@ -8069,6 +8140,8 @@ extern hashval_t iterative_hash_constraint (tree, hashval_t); extern hashval_t hash_atomic_constraint (tree); extern void diagnose_constraints (location_t, tree, tree); +extern void note_failed_type_completion_for_satisfaction (tree); + /* A structural hasher for ATOMIC_CONSTRs. */ struct atom_hasher : default_hash_traits<tree> @@ -8172,6 +8245,8 @@ struct uid_sensitive_constexpr_evaluation_checker bool evaluation_restricted_p () const; }; +void cp_tree_c_finish_parsing (); + /* In cp-ubsan.c */ extern void cp_ubsan_maybe_instrument_member_call (tree); extern void cp_ubsan_instrument_member_accesses (tree *); diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c index 183bd23..3dabb6a 100644 --- a/gcc/cp/cp-ubsan.c +++ b/gcc/cp/cp-ubsan.c @@ -1,5 +1,5 @@ /* UndefinedBehaviorSanitizer, undefined behavior detector. - Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copyright (C) 2014-2021 Free Software Foundation, Inc. Contributed by Jakub Jelinek <jakub@redhat.com> This file is part of GCC. diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index bcd7c5a..e809f0e 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1,5 +1,5 @@ /* Language-level data type conversion for GNU C++. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -599,11 +599,14 @@ ignore_overflows (tree expr, tree orig) } /* Fold away simple conversions, but make sure TREE_OVERFLOW is set - properly. */ + properly and propagate TREE_NO_WARNING if folding EXPR results + in the same expression code. */ tree cp_fold_convert (tree type, tree expr) { + bool nowarn = TREE_NO_WARNING (expr); + tree conv; if (TREE_TYPE (expr) == type) conv = expr; @@ -626,6 +629,10 @@ cp_fold_convert (tree type, tree expr) conv = fold_convert (type, expr); conv = ignore_overflows (conv, expr); } + + if (nowarn && TREE_CODE (expr) == TREE_CODE (conv)) + TREE_NO_WARNING (conv) = nowarn; + return conv; } @@ -1031,6 +1038,9 @@ cp_get_callee_fndecl_nofold (tree call) static void maybe_warn_nodiscard (tree expr, impl_conv_void implicit) { + if (!warn_unused_result || c_inhibit_evaluation_warnings) + return; + tree call = expr; if (TREE_CODE (expr) == TARGET_EXPR) call = TARGET_EXPR_INITIAL (expr); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index b97f70e..a22eea5 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1,5 +1,5 @@ /* Implementation of subroutines for the GNU C++ pretty-printer. - Copyright (C) 2003-2020 Free Software Foundation, Inc. + Copyright (C) 2003-2021 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> This file is part of GCC. @@ -1381,6 +1381,10 @@ cxx_pretty_printer::simple_type_specifier (tree t) pp_cxx_right_paren (this); break; + case NULLPTR_TYPE: + pp_cxx_ws_string (this, "std::nullptr_t"); + break; + default: c_pretty_printer::simple_type_specifier (t); break; @@ -1408,6 +1412,7 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t) case TYPE_DECL: case BOUND_TEMPLATE_TEMPLATE_PARM: case DECLTYPE_TYPE: + case NULLPTR_TYPE: pp_cxx_cv_qualifier_seq (pp, t); pp->simple_type_specifier (t); break; @@ -1873,6 +1878,7 @@ cxx_pretty_printer::type_id (tree t) case TYPEOF_TYPE: case UNDERLYING_TYPE: case DECLTYPE_TYPE: + case NULLPTR_TYPE: case TEMPLATE_ID_EXPR: case OFFSET_TYPE: pp_cxx_type_specifier_seq (this, t); diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index 494f3fd..913201e 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -1,5 +1,5 @@ /* Interface for the GNU C++ pretty-printer. - Copyright (C) 2003-2020 Free Software Foundation, Inc. + Copyright (C) 2003-2021 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> This file is part of GCC. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7da8c65..3b9875e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1,5 +1,5 @@ /* Process declarations and variables for -*- C++ -*- compiler. - Copyright (C) 1988-2020 Free Software Foundation, Inc. + Copyright (C) 1988-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -146,6 +146,10 @@ tree static_aggregates; /* Like static_aggregates, but for thread_local variables. */ tree tls_aggregates; +/* A hash-map mapping from variable decls to the dynamic initializer for + the decl. This is currently only used by OpenMP. */ +decl_tree_map *dynamic_initializers; + /* -- end of C++ */ /* A node for the integer constant 2. */ @@ -2008,6 +2012,39 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (!validate_constexpr_redeclaration (olddecl, newdecl)) return error_mark_node; + if (modules_p () + && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL + && TREE_CODE (olddecl) != NAMESPACE_DECL + && !hiding) + { + if (DECL_ARTIFICIAL (olddecl)) + { + gcc_checking_assert (!(DECL_LANG_SPECIFIC (olddecl) + && DECL_MODULE_IMPORT_P (olddecl))); + if (!(global_purview_p () || not_module_p ())) + error ("declaration %qD conflicts with builtin", newdecl); + else + DECL_MODULE_EXPORT_P (olddecl) = DECL_MODULE_EXPORT_P (newdecl); + } + else + { + if (!module_may_redeclare (olddecl)) + { + error ("declaration %qD conflicts with import", newdecl); + inform (olddecl_loc, "import declared %q#D here", olddecl); + + return error_mark_node; + } + + if (DECL_MODULE_EXPORT_P (newdecl) + && !DECL_MODULE_EXPORT_P (olddecl)) + { + error ("conflicting exporting declaration %qD", newdecl); + inform (olddecl_loc, "previous declaration %q#D here", olddecl); + } + } + } + /* We have committed to returning OLDDECL at this point. */ /* If new decl is `static' and an `extern' was seen previously, @@ -2218,6 +2255,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) } } + DECL_MODULE_IMPORT_P (olddecl) + = DECL_MODULE_IMPORT_P (old_result) + = DECL_MODULE_IMPORT_P (newdecl); + return olddecl; } @@ -2836,6 +2877,20 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) memcpy ((char *) olddecl + sizeof (struct tree_common), (char *) newdecl + sizeof (struct tree_common), sizeof (struct tree_decl_common) - sizeof (struct tree_common)); + + if (DECL_LANG_SPECIFIC (olddecl) && DECL_TEMPLATE_INFO (olddecl)) + { + /* Repropagate the module information to the template. */ + tree tmpl = DECL_TI_TEMPLATE (olddecl); + + if (DECL_TEMPLATE_RESULT (tmpl) == olddecl) + { + DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (olddecl); + gcc_checking_assert (!DECL_MODULE_IMPORT_P (olddecl)); + DECL_MODULE_IMPORT_P (tmpl) = false; + } + } + switch (TREE_CODE (newdecl)) { case LABEL_DECL: @@ -4330,7 +4385,8 @@ cxx_init_decl_processing (void) gcc_assert (global_namespace == NULL_TREE); global_namespace = build_lang_decl (NAMESPACE_DECL, global_identifier, void_type_node); - TREE_PUBLIC (global_namespace) = 1; + TREE_PUBLIC (global_namespace) = true; + DECL_MODULE_EXPORT_P (global_namespace) = true; DECL_CONTEXT (global_namespace) = build_translation_unit_decl (get_identifier (main_input_filename)); /* Remember whether we want the empty class passing ABI change warning @@ -4629,6 +4685,9 @@ cxx_init_decl_processing (void) if (! supports_one_only ()) flag_weak = 0; + if (modules_p ()) + init_modules (parse_in); + make_fname_decl = cp_make_fname_decl; start_fname_decls (); @@ -5453,8 +5512,14 @@ start_decl (const cp_declarator *declarator, 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; + { + /* A function-scope decl of some namespace-scope decl. */ + DECL_LOCAL_DECL_P (decl) = true; + if (named_module_purview_p ()) + error_at (declarator->id_loc, + "block-scope extern declaration %q#D not permitted" + " in module purview", decl); + } /* Enter this declaration into the symbol table. Don't push the plain VAR_DECL for a variable template. */ @@ -5470,7 +5535,9 @@ start_decl (const cp_declarator *declarator, if (VAR_P (decl) && DECL_NAMESPACE_SCOPE_P (decl) && !TREE_PUBLIC (decl) && !was_public - && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl)) + && !DECL_THIS_STATIC (decl) && !DECL_ARTIFICIAL (decl) + /* But not templated variables. */ + && !(DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))) { /* This is a const variable with implicit 'static'. Set DECL_THIS_STATIC so we can tell it from variables that are @@ -7773,6 +7840,12 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, retrofit_lang_decl (decl); SET_DECL_DEPENDENT_INIT_P (decl, true); } + + if (VAR_P (decl) && DECL_REGISTER (decl) && asmspec) + { + set_user_assembler_name (decl, asmspec); + DECL_HARD_REGISTER (decl) = 1; + } return; } @@ -9878,6 +9951,8 @@ grokfndecl (tree ctype, && !processing_template_decl) deduce_noexcept_on_destructor (decl); + set_originating_module (decl); + decl = check_explicit_specialization (orig_declarator, decl, template_count, 2 * funcdef_flag + @@ -10122,6 +10197,8 @@ grokvardecl (tree type, TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); } + set_originating_module (decl); + if (decl_spec_seq_has_spec_p (declspecs, ds_thread)) { if (DECL_EXTERNAL (decl) || TREE_STATIC (decl)) @@ -11446,7 +11523,7 @@ grokdeclarator (const cp_declarator *declarator, /* An object declared as __attribute__((deprecated)) suppresses warnings of uses of other deprecated items. */ - temp_override<deprecated_states> ds (deprecated_state); + auto ds = make_temp_override (deprecated_state); if (attrlist && lookup_attribute ("deprecated", *attrlist)) deprecated_state = DEPRECATED_SUPPRESS; @@ -12170,10 +12247,12 @@ grokdeclarator (const cp_declarator *declarator, tree late_return_type = declarator->u.function.late_return_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)) + if (!funcdecl_p) + /* auto (*fp)() = f; is OK. */; + else if (current_class_type + && LAMBDA_TYPE_P (current_class_type)) /* OK for C++11 lambdas. */; else if (cxx_dialect < cxx14) { @@ -12965,6 +13044,8 @@ grokdeclarator (const cp_declarator *declarator, revert this subsequently if it determines that the clones should share a common implementation. */ DECL_ABSTRACT_P (decl) = true; + + set_originating_module (decl); } else if (current_class_type && constructor_name_p (unqualified_id, current_class_type)) @@ -13499,6 +13580,8 @@ grokdeclarator (const cp_declarator *declarator, ; /* We already issued a permerror. */ else if (decl && DECL_NAME (decl)) { + set_originating_module (decl, true); + if (initialized) /* Kludge: We need funcdef_flag to be true in do_friend for in-class defaulted functions, but that breaks grokfndecl. @@ -15135,6 +15218,41 @@ xref_tag_1 (enum tag_types tag_code, tree name, inform (location_of (t), "previous declaration %qD", t); return error_mark_node; } + + if (modules_p () + && how == TAG_how::CURRENT_ONLY) + { + tree decl = TYPE_NAME (t); + if (!module_may_redeclare (decl)) + { + error ("cannot declare %qD in a different module", decl); + inform (DECL_SOURCE_LOCATION (decl), "declared here"); + return error_mark_node; + } + + tree maybe_tmpl = decl; + if (CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t)) + maybe_tmpl = CLASSTYPE_TI_TEMPLATE (t); + + if (DECL_LANG_SPECIFIC (decl) + && DECL_MODULE_IMPORT_P (decl) + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + { + /* Push it into this TU's symbol slot. */ + gcc_checking_assert (current_namespace == CP_DECL_CONTEXT (decl)); + if (maybe_tmpl != decl) + /* We're in the template parm binding level. + Pushtag has logic to slide under that, but we're + not pushing a *new* type. */ + push_nested_namespace (CP_DECL_CONTEXT (decl)); + + pushdecl (maybe_tmpl); + if (maybe_tmpl != decl) + pop_nested_namespace (CP_DECL_CONTEXT (decl)); + } + + set_instantiating_module (maybe_tmpl); + } } return t; @@ -15479,6 +15597,19 @@ start_enum (tree name, tree enumtype, tree underlying_type, "previous definition here"); underlying_type = NULL_TREE; } + + if (modules_p ()) + { + if (!module_may_redeclare (TYPE_NAME (enumtype))) + { + error ("cannot define %qD in different module", + TYPE_NAME (enumtype)); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (enumtype)), + "declared here"); + enumtype = error_mark_node; + } + set_instantiating_module (TYPE_NAME (enumtype)); + } } if (!enumtype || TREE_CODE (enumtype) != ENUMERAL_TYPE @@ -15739,6 +15870,11 @@ finish_enum_value_list (tree enumtype) else underlying_type = ENUM_UNDERLYING_TYPE (enumtype); + /* If the enum is exported, mark the consts too. */ + bool export_p = (UNSCOPED_ENUM_P (enumtype) + && DECL_MODULE_EXPORT_P (TYPE_STUB_DECL (enumtype)) + && at_namespace_scope_p ()); + /* Convert each of the enumerators to the type of the underlying type of the enumeration. */ for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values)) @@ -15761,6 +15897,8 @@ finish_enum_value_list (tree enumtype) TREE_TYPE (value) = enumtype; } DECL_INITIAL (decl) = value; + if (export_p) + DECL_MODULE_EXPORT_P (decl) = true; } /* Fix up all variant types of this enum type. */ @@ -17358,10 +17496,25 @@ grokmethod (cp_decl_specifier_seq *declspecs, check_template_shadow (fndecl); - if (TREE_PUBLIC (fndecl)) - DECL_COMDAT (fndecl) = 1; - DECL_DECLARED_INLINE_P (fndecl) = 1; - DECL_NO_INLINE_WARNING_P (fndecl) = 1; + /* p1779 ABI-Isolation makes inline not a default for in-class + definitions in named module purview. If the user explicitly + made it inline, grokdeclarator will already have done the right + things. */ + if ((!named_module_purview_p () + || flag_module_implicit_inline + /* Lambda's operator function remains inline. */ + || LAMBDA_TYPE_P (DECL_CONTEXT (fndecl))) + /* If the user explicitly asked for this to be inline, we don't + need to do more, but more importantly we want to warn if we + can't inline it. */ + && !DECL_DECLARED_INLINE_P (fndecl)) + { + if (TREE_PUBLIC (fndecl)) + DECL_COMDAT (fndecl) = 1; + DECL_DECLARED_INLINE_P (fndecl) = 1; + /* It's ok if we can't inline this. */ + DECL_NO_INLINE_WARNING_P (fndecl) = 1; + } /* We process method specializations in finish_struct_1. */ if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl)) @@ -17728,6 +17881,7 @@ require_deduced_type (tree decl, tsubst_flags_t complain) /* We probably already complained about deduction failure. */; else if (complain & tf_error) error ("use of %qD before deduction of %<auto%>", decl); + note_failed_type_completion_for_satisfaction (decl); return false; } return true; diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h index 3252dd8..387d807 100644 --- a/gcc/cp/decl.h +++ b/gcc/cp/decl.h @@ -1,5 +1,5 @@ /* Variables and structures for declaration processing. - Copyright (C) 1993-2020 Free Software Foundation, Inc. + Copyright (C) 1993-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 46069cb..b087753 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1,5 +1,5 @@ /* Process declarations and variables for C++ compiler. - Copyright (C) 1988-2020 Free Software Foundation, Inc. + Copyright (C) 1988-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "c-family/c-ada-spec.h" #include "asan.h" +#include "optabs-query.h" /* Id for dumping the raw trees. */ int raw_dump_id; @@ -2357,9 +2358,6 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data) int this_vis = VISIBILITY_DEFAULT; if (! TYPE_P (*tp)) *walk_subtrees = 0; - else if (typedef_variant_p (*tp)) - /* Look through typedefs despite cp_walk_subtrees. */ - this_vis = type_visibility (DECL_ORIGINAL_TYPE (TYPE_NAME (*tp))); else if (OVERLOAD_TYPE_P (*tp) && !TREE_PUBLIC (TYPE_MAIN_DECL (*tp))) { @@ -2378,6 +2376,10 @@ min_vis_r (tree *tp, int *walk_subtrees, void *data) if (this_vis > *vis_p) *vis_p = this_vis; + /* Tell cp_walk_subtrees to look through typedefs. */ + if (*walk_subtrees == 1) + *walk_subtrees = 2; + return NULL; } @@ -3297,18 +3299,34 @@ get_guard (tree decl) return guard; } +/* Returns true if accessing the GUARD atomic is expensive, + i.e. involves a call to __sync_synchronize or similar. + In this case let __cxa_guard_acquire handle the atomics. */ + +static bool +is_atomic_expensive_p (machine_mode mode) +{ + if (!flag_inline_atomics) + return true; + + if (!can_compare_and_swap_p (mode, false) || !can_atomic_load_p (mode)) + return true; + + return false; +} + /* Return an atomic load of src with the appropriate memory model. */ static tree -build_atomic_load_byte (tree src, HOST_WIDE_INT model) +build_atomic_load_type (tree src, HOST_WIDE_INT model, tree type) { - tree ptr_type = build_pointer_type (char_type_node); + tree ptr_type = build_pointer_type (type); tree mem_model = build_int_cst (integer_type_node, model); tree t, addr, val; unsigned int size; int fncode; - size = tree_to_uhwi (TYPE_SIZE_UNIT (char_type_node)); + size = tree_to_uhwi (TYPE_SIZE_UNIT (type)); fncode = BUILT_IN_ATOMIC_LOAD_N + exact_log2 (size) + 1; t = builtin_decl_implicit ((enum built_in_function) fncode); @@ -3351,7 +3369,15 @@ get_guard_cond (tree guard, bool thread_safe) if (!thread_safe) guard = get_guard_bits (guard); else - guard = build_atomic_load_byte (guard, MEMMODEL_ACQUIRE); + { + tree type = targetm.cxx.guard_mask_bit () + ? TREE_TYPE (guard) : char_type_node; + + if (is_atomic_expensive_p (TYPE_MODE (type))) + guard = integer_zero_node; + else + guard = build_atomic_load_type (guard, MEMMODEL_ACQUIRE, type); + } /* Mask off all but the low bit. */ if (targetm.cxx.guard_mask_bit ()) @@ -3636,35 +3662,45 @@ generate_tls_wrapper (tree fn) static tree start_objects (int method_type, int initp) { - tree body; - tree fndecl; - char type[14]; - /* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'. */ + int module_init = 0; - if (initp != DEFAULT_INIT_PRIORITY) + if (initp == DEFAULT_INIT_PRIORITY && method_type == 'I') + module_init = module_initializer_kind (); + + tree name = NULL_TREE; + if (module_init > 0) + name = mangle_module_global_init (0); + else { - char joiner; + char type[14]; + unsigned len = sprintf (type, "sub_%c", method_type); + if (initp != DEFAULT_INIT_PRIORITY) + { + char joiner = '_'; #ifdef JOINER - joiner = JOINER; -#else - joiner = '_'; + joiner = JOINER; #endif + type[len++] = joiner; + sprintf (type + len, "%.5u", initp); + } + name = get_file_function_name (type); + } - sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp); + tree fntype = build_function_type (void_type_node, void_list_node); + tree fndecl = build_lang_decl (FUNCTION_DECL, name, fntype); + DECL_CONTEXT (fndecl) = FROB_CONTEXT (global_namespace); + if (module_init > 0) + { + SET_DECL_ASSEMBLER_NAME (fndecl, name); + TREE_PUBLIC (fndecl) = true; + determine_visibility (fndecl); } else - sprintf (type, "sub_%c", method_type); - - fndecl = build_lang_decl (FUNCTION_DECL, - get_file_function_name (type), - build_function_type_list (void_type_node, - NULL_TREE)); + TREE_PUBLIC (fndecl) = 0; start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED); - TREE_PUBLIC (current_function_decl) = 0; - /* Mark as artificial because it's not explicitly in the user's source code. */ DECL_ARTIFICIAL (current_function_decl) = 1; @@ -3678,7 +3714,35 @@ start_objects (int method_type, int initp) else DECL_GLOBAL_DTOR_P (current_function_decl) = 1; - body = begin_compound_stmt (BCS_FN_BODY); + tree body = begin_compound_stmt (BCS_FN_BODY); + + if (module_init > 0) + { + // 'static bool __in_chrg = false; + // if (__inchrg) return; + // __inchrg = true + tree var = build_lang_decl (VAR_DECL, in_charge_identifier, + boolean_type_node); + DECL_CONTEXT (var) = fndecl; + DECL_ARTIFICIAL (var) = true; + TREE_STATIC (var) = true; + pushdecl (var); + cp_finish_decl (var, NULL_TREE, false, NULL_TREE, 0); + + tree if_stmt = begin_if_stmt (); + finish_if_stmt_cond (var, if_stmt); + finish_return_stmt (NULL_TREE); + finish_then_clause (if_stmt); + finish_if_stmt (if_stmt); + + tree assign = build2 (MODIFY_EXPR, boolean_type_node, + var, boolean_true_node); + TREE_SIDE_EFFECTS (assign) = true; + finish_expr_stmt (assign); + } + + if (module_init) + module_add_import_initializers (); return body; } @@ -3689,11 +3753,9 @@ start_objects (int method_type, int initp) static void finish_objects (int method_type, int initp, tree body) { - tree fn; - /* Finish up. */ finish_compound_stmt (body); - fn = finish_function (/*inline_p=*/false); + tree fn = finish_function (/*inline_p=*/false); if (method_type == 'I') { @@ -4228,50 +4290,50 @@ static void generate_ctor_or_dtor_function (bool constructor_p, int priority, location_t *locus) { - char function_key; - tree fndecl; - tree body; - size_t i; - input_location = *locus; - /* ??? */ - /* Was: locus->line++; */ /* We use `I' to indicate initialization and `D' to indicate destruction. */ - function_key = constructor_p ? 'I' : 'D'; + char function_key = constructor_p ? 'I' : 'D'; /* We emit the function lazily, to avoid generating empty global constructors and destructors. */ - body = NULL_TREE; + tree body = NULL_TREE; - /* For Objective-C++, we may need to initialize metadata found in this module. - This must be done _before_ any other static initializations. */ - if (c_dialect_objc () && (priority == DEFAULT_INIT_PRIORITY) - && constructor_p && objc_static_init_needed_p ()) + if (constructor_p && priority == DEFAULT_INIT_PRIORITY) { - body = start_objects (function_key, priority); - objc_generate_static_init_call (NULL_TREE); + bool objc = c_dialect_objc () && objc_static_init_needed_p (); + + /* We may have module initialization to emit and/or insert + before other intializations. */ + if (module_initializer_kind () || objc) + body = start_objects (function_key, priority); + + /* For Objective-C++, we may need to initialize metadata found + in this module. This must be done _before_ any other static + initializations. */ + if (objc) + objc_generate_static_init_call (NULL_TREE); } /* Call the static storage duration function with appropriate arguments. */ + tree fndecl; + size_t i; FOR_EACH_VEC_SAFE_ELT (ssdf_decls, i, fndecl) { /* Calls to pure or const functions will expand to nothing. */ if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE))) { - tree call; - if (! body) body = start_objects (function_key, priority); - call = cp_build_function_call_nary (fndecl, tf_warning_or_error, - build_int_cst (NULL_TREE, - constructor_p), - build_int_cst (NULL_TREE, - priority), - NULL_TREE); + tree call = cp_build_function_call_nary (fndecl, tf_warning_or_error, + build_int_cst (NULL_TREE, + constructor_p), + build_int_cst (NULL_TREE, + priority), + NULL_TREE); finish_expr_stmt (call); } } @@ -4470,6 +4532,10 @@ no_linkage_error (tree decl) /* In C++11 it's ok if the decl is defined. */ return; + if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl)) + /* An imported decl is ok. */ + 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 @@ -4822,11 +4888,7 @@ lower_var_init () void c_parse_final_cleanups (void) { - tree vars; - bool reconsider; size_t i; - unsigned ssdf_count = 0; - int retries = 0; tree decl; locus_at_end_of_parsing = input_location; @@ -4892,11 +4954,10 @@ c_parse_final_cleanups (void) /* Track vtables we want to emit that refer to consteval functions. */ auto_vec<tree> consteval_vtables; - do + int retries = 0; + unsigned ssdf_count = 0; + for (bool reconsider = true; reconsider; retries++) { - tree t; - tree decl; - reconsider = false; /* If there are templates that we've put off instantiating, do @@ -4904,11 +4965,17 @@ c_parse_final_cleanups (void) instantiate_pending_templates (retries); ggc_collect (); + if (header_module_p ()) + /* A header modules initializations are handled in its + importer. */ + continue; + /* Write out virtual tables as required. Writing out the virtual table for a template class may cause the instantiation of members of that class. If we write out vtables then we remove the class from our list so we don't have to look at it again. */ + tree t; for (i = keyed_classes->length (); keyed_classes->iterate (--i, &t);) if (maybe_emit_vtables (t, consteval_vtables)) @@ -4938,10 +5005,15 @@ c_parse_final_cleanups (void) aggregates added during the initialization of these will be initialized in the correct order when we next come around the loop. */ - vars = prune_vars_needing_no_initialization (&static_aggregates); - - if (vars) + if (tree vars = prune_vars_needing_no_initialization (&static_aggregates)) { + if (flag_openmp) + /* Add initializer information from VARS into + DYNAMIC_INITIALIZERS. */ + for (t = vars; t; t = TREE_CHAIN (t)) + hash_map_safe_put<hm_ggc> (dynamic_initializers, + TREE_VALUE (t), TREE_PURPOSE (t)); + /* We need to start a new initialization function each time through the loop. That's because we need to know which vtables have been referenced, and TREE_SYMBOL_REFERENCED @@ -4987,7 +5059,6 @@ c_parse_final_cleanups (void) instantiations, etc. */ reconsider = true; ssdf_count++; - /* ??? was: locus_at_end_of_parsing.line++; */ } /* Now do the same for thread_local variables. */ @@ -5097,14 +5168,14 @@ c_parse_final_cleanups (void) if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl)) DECL_EXTERNAL (decl) = 0; } + if (vec_safe_length (pending_statics) != 0 && wrapup_global_declarations (pending_statics->address (), pending_statics->length ())) reconsider = true; - - retries++; } - while (reconsider); + + finish_module_processing (parse_in); lower_var_init (); @@ -5121,6 +5192,10 @@ c_parse_final_cleanups (void) #pragma interface, etc.) we decided not to emit the definition here. */ && !DECL_INITIAL (decl) + /* A defaulted fn in a header module can be synthesized on + demand later. (In non-header modules we should have + synthesized it above.) */ + && !(DECL_DEFAULTED_FN (decl) && header_module_p ()) /* Don't complain if the template was defined. */ && !(DECL_TEMPLATE_INSTANTIATION (decl) && DECL_INITIAL (DECL_TEMPLATE_RESULT @@ -5154,9 +5229,8 @@ c_parse_final_cleanups (void) splay_tree_foreach (priority_info_map, generate_ctor_and_dtor_functions_for_priority, /*data=*/&locus_at_end_of_parsing); - else if (c_dialect_objc () && objc_static_init_needed_p ()) - /* If this is obj-c++ and we need a static init, call - generate_ctor_or_dtor_function. */ + else if ((c_dialect_objc () && objc_static_init_needed_p ()) + || module_initializer_kind ()) generate_ctor_or_dtor_function (/*constructor_p=*/true, DEFAULT_INIT_PRIORITY, &locus_at_end_of_parsing); @@ -5165,6 +5239,8 @@ c_parse_final_cleanups (void) if (priority_info_map) splay_tree_delete (priority_info_map); + fini_modules (); + /* Generate any missing aliases. */ maybe_apply_pending_pragma_weaks (); @@ -5182,6 +5258,7 @@ c_parse_final_cleanups (void) perform_deferred_noexcept_checks (); fini_constexpr (); + cp_tree_c_finish_parsing (); clear_consteval_vfns (consteval_vtables); /* The entire file is now complete. If requested, dump everything diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index 81d2c16..caca95a 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -1,5 +1,5 @@ /* Tree-dumping functionality for intermediate representation. - Copyright (C) 1999-2020 Free Software Foundation, Inc. + Copyright (C) 1999-2021 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com> This file is part of GCC. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index d11591d..5213a80 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1,6 +1,6 @@ /* Call-backs for C++ error reporting. This code is non-reentrant. - Copyright (C) 1993-2020 Free Software Foundation, Inc. + Copyright (C) 1993-2021 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify @@ -179,6 +179,38 @@ cxx_initialize_diagnostics (diagnostic_context *context) pp->m_format_postprocessor = new cxx_format_postprocessor (); } +/* Dump an '@module' name suffix for DECL, if any. */ + +static void +dump_module_suffix (cxx_pretty_printer *pp, tree decl) +{ + if (!modules_p ()) + return; + + if (!DECL_CONTEXT (decl)) + return; + + if (TREE_CODE (decl) != CONST_DECL + || !UNSCOPED_ENUM_P (DECL_CONTEXT (decl))) + { + if (!DECL_NAMESPACE_SCOPE_P (decl)) + return; + + if (TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl) + && (TREE_PUBLIC (decl) || !TREE_PUBLIC (CP_DECL_CONTEXT (decl)))) + return; + } + + if (unsigned m = get_originating_module (decl)) + if (const char *n = module_name (m, false)) + { + pp_character (pp, '@'); + pp->padding = pp_none; + pp_string (pp, n); + } +} + /* Dump a scope, if deemed necessary. */ static void @@ -771,6 +803,8 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) else pp_cxx_tree_identifier (pp, DECL_NAME (decl)); + dump_module_suffix (pp, decl); + if (tmplate) dump_template_parms (pp, TYPE_TEMPLATE_INFO (t), !CLASSTYPE_USE_TEMPLATE (t), @@ -1077,6 +1111,9 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) pp_string (pp, M_("<structured bindings>")); else pp_string (pp, M_("<anonymous>")); + + dump_module_suffix (pp, t); + if (flags & TFF_DECL_SPECIFIERS) dump_type_suffix (pp, type, flags); } @@ -1894,6 +1931,8 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags) else dump_decl (pp, name, flags); + dump_module_suffix (pp, t); + if (DECL_TEMPLATE_INFO (t) && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t) && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL @@ -2313,7 +2352,8 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) if (INDIRECT_REF_P (ob)) { ob = TREE_OPERAND (ob, 0); - if (!is_this_parameter (ob)) + if (!is_this_parameter (ob) + && !is_dummy_object (ob)) { dump_expr (pp, ob, flags | TFF_EXPR_IN_PARENS); if (TYPE_REF_P (TREE_TYPE (ob))) @@ -2378,32 +2418,8 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) break; case MEM_REF: - if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR - && integer_zerop (TREE_OPERAND (t, 1))) - dump_expr (pp, TREE_OPERAND (TREE_OPERAND (t, 0), 0), flags); - else - { - pp_cxx_star (pp); - if (!integer_zerop (TREE_OPERAND (t, 1))) - { - pp_cxx_left_paren (pp); - if (!integer_onep (TYPE_SIZE_UNIT - (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))))) - { - pp_cxx_left_paren (pp); - dump_type (pp, ptr_type_node, flags); - pp_cxx_right_paren (pp); - } - } - dump_expr (pp, TREE_OPERAND (t, 0), flags); - if (!integer_zerop (TREE_OPERAND (t, 1))) - { - pp_cxx_ws_string (pp, "+"); - dump_expr (pp, fold_convert (ssizetype, TREE_OPERAND (t, 1)), - flags); - pp_cxx_right_paren (pp); - } - } + /* Delegate to the base "C" pretty printer. */ + pp->c_pretty_printer::unary_expression (t); break; case TARGET_MEM_REF: diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 0f6c76b..0bbc229 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1,5 +1,5 @@ /* Handle exceptional things in C++. - Copyright (C) 1989-2020 Free Software Foundation, Inc. + Copyright (C) 1989-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann <tiemann@cygnus.com> Rewritten by Mike Stump <mrs@cygnus.com>, based upon an initial re-implementation courtesy Tad Hunt. @@ -1101,7 +1101,7 @@ maybe_noexcept_warning (tree fn) && (!DECL_IN_SYSTEM_HEADER (fn) || global_dc->dc_warn_system_headers)) { - temp_override<bool> s (global_dc->dc_warn_system_headers, true); + auto s = make_temp_override (global_dc->dc_warn_system_headers, true); auto_diagnostic_group d; if (warning (OPT_Wnoexcept, "noexcept-expression evaluates to %<false%> " "because of a call to %qD", fn)) diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index aa60593..480e740 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -1,6 +1,6 @@ /* Convert language-specific tree expression to rtl instructions, for GNU compiler. - Copyright (C) 1988-2020 Free Software Foundation, Inc. + Copyright (C) 1988-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 56fa960..ee73adb 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -1,5 +1,5 @@ /* Help friends in C++. - Copyright (C) 1997-2020 Free Software Foundation, Inc. + Copyright (C) 1997-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c index 0f17148..3c9bd14 100644 --- a/gcc/cp/g++spec.c +++ b/gcc/cp/g++spec.c @@ -1,5 +1,5 @@ /* Specific flags and argument handling of the C++ front end. - Copyright (C) 1996-2020 Free Software Foundation, Inc. + Copyright (C) 1996-2021 Free Software Foundation, Inc. This file is part of GCC. @@ -49,6 +49,34 @@ along with GCC; see the file COPYING3. If not see #define LIBSTDCXX_STATIC NULL #endif +#ifndef LIBCXX +#define LIBCXX "c++" +#endif +#ifndef LIBCXX_PROFILE +#define LIBCXX_PROFILE LIBCXX +#endif +#ifndef LIBCXX_STATIC +#define LIBCXX_STATIC NULL +#endif + +#ifndef LIBCXXABI +#define LIBCXXABI "c++abi" +#endif +#ifndef LIBCXXABI_PROFILE +#define LIBCXXABI_PROFILE LIBCXXABI +#endif +#ifndef LIBCXXABI_STATIC +#define LIBCXXABI_STATIC NULL +#endif + +/* The values used here must match those of the stdlib_kind enumeration + in c.opt. */ +enum stdcxxlib_kind +{ + USE_LIBSTDCXX = 1, + USE_LIBCXX = 2 +}; + void lang_specific_driver (struct cl_decoded_option **in_decoded_options, unsigned int *in_decoded_options_count, @@ -59,13 +87,16 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* If nonzero, the user gave us the `-p' or `-pg' flag. */ int saw_profile_flag = 0; - /* What do with libstdc++: - -1 means we should not link in libstdc++ - 0 means we should link in libstdc++ if it is needed - 1 means libstdc++ is needed and should be linked in. - 2 means libstdc++ is needed and should be linked statically. */ + /* What action to take for the c++ runtime library: + -1 means we should not link it in. + 0 means we should link it if it is needed. + 1 means it is needed and should be linked in. + 2 means it is needed but should be linked statically. */ int library = 0; + /* Which c++ runtime library to link. */ + stdcxxlib_kind which_library = USE_LIBSTDCXX; + /* The number of arguments being added to what's in argv, other than libraries. We use this to track the number of times we've inserted -xc++/-xnone. */ @@ -194,6 +225,10 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, args[i] |= SKIPOPT; break; + case OPT_stdlib_: + which_library = (stdcxxlib_kind) decoded_options[i].value; + break; + case OPT_SPECIAL_input_file: { int len; @@ -250,6 +285,13 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* Add one for shared_libgcc or extra static library. */ num_args = argc + added + need_math + (library > 0) * 4 + 1; + /* For libc++, on most platforms, the ABI library (usually called libc++abi) + is provided as a separate DSO, which we must also append. + However, a platform might have the ability to forward the ABI library + from libc++, or combine it in some other way; in that case, LIBCXXABI + should be set to NULL to signal that it need not be appended. */ + if (which_library == USE_LIBCXX && LIBCXXABI != NULL) + num_args += 4; new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args); i = 0; @@ -323,9 +365,25 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, j++; } #endif - generate_option (OPT_l, - saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX, 1, - CL_DRIVER, &new_decoded_options[j]); + if (which_library == USE_LIBCXX) + { + generate_option (OPT_l, + saw_profile_flag ? LIBCXX_PROFILE : LIBCXX, 1, + CL_DRIVER, &new_decoded_options[j]); + if (LIBCXXABI != NULL) + { + j++; + added_libraries++; + generate_option (OPT_l, + saw_profile_flag ? LIBCXXABI_PROFILE + : LIBCXXABI, 1, + CL_DRIVER, &new_decoded_options[j]); + } + } + else + generate_option (OPT_l, + saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX, 1, + CL_DRIVER, &new_decoded_options[j]); added_libraries++; j++; /* Add target-dependent static library, if necessary. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 0b98f33..131da1a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,5 +1,5 @@ /* Handle initialization things in C++. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -187,7 +187,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p, else if (NULLPTR_TYPE_P (type)) init = build_int_cst (type, 0); else if (SCALAR_TYPE_P (type)) - init = fold (convert (type, integer_zero_node)); + init = build_zero_cst (type); else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type))) { tree field; @@ -288,10 +288,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p, else if (VECTOR_TYPE_P (type)) init = build_zero_cst (type); else - { - gcc_assert (TYPE_REF_P (type)); - init = build_zero_cst (type); - } + gcc_assert (TYPE_REF_P (type)); /* In all cases, the initializer is a constant. */ if (init) @@ -880,7 +877,7 @@ perform_member_init (tree member, tree init) } if (init == error_mark_node) return; - if (DECL_SIZE (member) && integer_zerop (DECL_SIZE (member)) + if (is_empty_field (member) && !TREE_SIDE_EFFECTS (init)) /* Don't add trivial initialization of an empty base/field, as they might not be ordered the way the back-end expects. */ @@ -1922,7 +1919,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, in an exception region. */; else init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, - flags, complain); + flags, complain | tf_no_cleanup); if (TREE_CODE (init) == MUST_NOT_THROW_EXPR) /* We need to protect the initialization of a catch parm with a diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 1a1647f..586b7ff 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998-2020 Free Software Foundation, Inc. + Copyright (C) 1998-2021 Free Software Foundation, Inc. This file is part of GCC. @@ -1114,6 +1114,8 @@ maybe_add_lambda_conv_op (tree type) while (src) { tree new_node = copy_node (src); + /* We set DECL_CONTEXT of NEW_NODE to the statfn below. + Notice this is creating a recursive type! */ /* Clear TREE_ADDRESSABLE on thunk arguments. */ TREE_ADDRESSABLE (new_node) = 0; @@ -1393,6 +1395,12 @@ record_lambda_scope (tree lambda) { LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope; LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; + if (lambda_scope) + { + tree closure = LAMBDA_EXPR_CLOSURE (lambda); + gcc_checking_assert (closure); + maybe_attach_decl (lambda_scope, TYPE_NAME (closure)); + } } /* This lambda is an instantiation of a lambda in a template default argument diff --git a/gcc/cp/lang-specs.h b/gcc/cp/lang-specs.h index 1388aae..8902ae1 100644 --- a/gcc/cp/lang-specs.h +++ b/gcc/cp/lang-specs.h @@ -1,5 +1,5 @@ /* Definitions for specs for C++. - Copyright (C) 1995-2020 Free Software Foundation, Inc. + Copyright (C) 1995-2021 Free Software Foundation, Inc. This file is part of GCC. @@ -52,9 +52,11 @@ along with GCC; see the file COPYING3. If not see " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" " %{fmodules-ts:-fmodule-header %{fpreprocessed:-fdirectives-only}}" " %(cc1_options) %2" - " %{!S:-o %g.s%V}" - " %{!fsyntax-only:%{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}}}}", + " %{!fsyntax-only:" + " %{!S:-o %g.s%V}" + " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" + " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}" + "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++-system-header", "%{E|M|MM:cc1plus -E" @@ -68,11 +70,14 @@ along with GCC; see the file COPYING3. If not see " %{fmodules-ts:-fdirectives-only}" " %{save-temps*:%b.ii} %{!save-temps*:%g.ii}}" " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" - " %{fmodules-ts:-fmodule-header=system %{fpreprocessed:-fdirectives-only}}" + " %{fmodules-ts:-fmodule-header=system" + " %{fpreprocessed:-fdirectives-only}}" " %(cc1_options) %2" - " %{!S:-o %g.s%V}" - " %{!fsyntax-only:%{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}}}}", + " %{!fsyntax-only:" + " %{!S:-o %g.s%V}" + " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" + " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}" + "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++-user-header", "%{E|M|MM:cc1plus -E" @@ -88,9 +93,11 @@ along with GCC; see the file COPYING3. If not see " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" " %{fmodules-ts:-fmodule-header=user %{fpreprocessed:-fdirectives-only}}" " %(cc1_options) %2" - " %{!S:-o %g.s%V}" - " %{!fsyntax-only:%{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}}}}", + " %{!fsyntax-only:" + " %{!S:-o %g.s%V}" + " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" + " %{!o*:--output-pch=%i.gch}%W{o*:--output-pch=%*}}}}}" + "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++", "%{E|M|MM:cc1plus -E %(cpp_options) %2 %(cpp_debug_options)}" @@ -101,13 +108,16 @@ along with GCC; see the file COPYING3. If not see " %{save-temps*:%b.ii} %{!save-temps*:%g.ii}}" " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" " %(cc1_options) %2" - " %{fmodule-only:%{!S:-o %g.s%V}}" - " %{!fsyntax-only:%{!fmodule-only:%(invoke_as)}}}}}", + " %{!fsyntax-only:" + " %{fmodule-only:%{!S:-o %g.s%V}}" + " %{!fmodule-only:%(invoke_as)}}" + "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {".ii", "@c++-cpp-output", 0, 0, 0}, {"@c++-cpp-output", "%{!E:%{!M:%{!MM:" " cc1plus -fpreprocessed %i %(cc1_options) %2" - " %{fmodule-only:%{!S:-o %g.s%V}}" - " %{!fsyntax-only:%{!fmodule-only:%{!fmodule-header*:" - " %(invoke_as)}}}}}}", 0, 0, 0}, + " %{!fsyntax-only:" + " %{fmodule-only:%{!S:-o %g.s%V}}" + " %{!fmodule-only:%{!fmodule-header*:%(invoke_as)}}}" + "}}}", 0, 0, 0}, diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 795f571..848f3d9 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -1,5 +1,5 @@ /* Separate lexical analyzer for GNU C++. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-objc.h" #include "gcc-rich-location.h" #include "cp-name-hint.h" +#include "langhooks.h" static int interface_strcmp (const char *); static void init_cp_pragma (void); @@ -380,7 +381,206 @@ interface_strcmp (const char* s) return 1; } - +/* We've just read a cpp-token, figure out our next state. Hey, this + is a hand-coded co-routine! */ + +struct module_token_filter +{ + enum state + { + idle, + module_first, + module_cont, + module_end, + }; + + enum state state : 8; + bool is_import : 1; + bool got_export : 1; + bool got_colon : 1; + bool want_dot : 1; + + location_t token_loc; + cpp_reader *reader; + module_state *module; + module_state *import; + + module_token_filter (cpp_reader *reader) + : state (idle), is_import (false), + got_export (false), got_colon (false), want_dot (false), + token_loc (UNKNOWN_LOCATION), + reader (reader), module (NULL), import (NULL) + { + }; + + /* Process the next token. Note we cannot see CPP_EOF inside a + pragma -- a CPP_PRAGMA_EOL always happens. */ + uintptr_t resume (int type, int keyword, tree value, location_t loc) + { + unsigned res = 0; + + switch (state) + { + case idle: + if (type == CPP_KEYWORD) + switch (keyword) + { + default: + break; + + case RID__EXPORT: + got_export = true; + res = lang_hooks::PT_begin_pragma; + break; + + case RID__IMPORT: + is_import = true; + /* FALLTHRU */ + case RID__MODULE: + state = module_first; + want_dot = false; + got_colon = false; + token_loc = loc; + import = NULL; + if (!got_export) + res = lang_hooks::PT_begin_pragma; + break; + } + break; + + case module_first: + if (is_import && type == CPP_HEADER_NAME) + { + /* A header name. The preprocessor will have already + done include searching and canonicalization. */ + state = module_end; + goto header_unit; + } + + if (type == CPP_PADDING || type == CPP_COMMENT) + break; + + state = module_cont; + if (type == CPP_COLON && module) + { + got_colon = true; + import = module; + break; + } + /* FALLTHROUGH */ + + case module_cont: + switch (type) + { + case CPP_PADDING: + case CPP_COMMENT: + break; + + default: + /* If we ever need to pay attention to attributes for + header modules, more logic will be needed. */ + state = module_end; + break; + + case CPP_COLON: + if (got_colon) + state = module_end; + got_colon = true; + /* FALLTHROUGH */ + case CPP_DOT: + if (!want_dot) + state = module_end; + want_dot = false; + break; + + case CPP_PRAGMA_EOL: + goto module_end; + + case CPP_NAME: + if (want_dot) + { + /* Got name instead of [.:]. */ + state = module_end; + break; + } + header_unit: + import = get_module (value, import, got_colon); + want_dot = true; + break; + } + break; + + case module_end: + if (type == CPP_PRAGMA_EOL) + { + module_end:; + /* End of the directive, handle the name. */ + if (import) + if (module_state *m + = preprocess_module (import, token_loc, module != NULL, + is_import, got_export, reader)) + if (!module) + module = m; + + is_import = got_export = false; + state = idle; + } + break; + } + + return res; + } +}; + +/* Initialize or teardown. */ + +uintptr_t +module_token_cdtor (cpp_reader *pfile, uintptr_t data_) +{ + if (module_token_filter *filter = reinterpret_cast<module_token_filter *> (data_)) + { + preprocessed_module (pfile); + delete filter; + data_ = 0; + } + else if (modules_p ()) + data_ = reinterpret_cast<uintptr_t > (new module_token_filter (pfile)); + + return data_; +} + +uintptr_t +module_token_lang (int type, int keyword, tree value, location_t loc, + uintptr_t data_) +{ + module_token_filter *filter = reinterpret_cast<module_token_filter *> (data_); + return filter->resume (type, keyword, value, loc); +} + +uintptr_t +module_token_pre (cpp_reader *pfile, const cpp_token *tok, uintptr_t data_) +{ + if (!tok) + return module_token_cdtor (pfile, data_); + + int type = tok->type; + int keyword = RID_MAX; + tree value = NULL_TREE; + + if (tok->type == CPP_NAME) + { + value = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok->val.node.node)); + if (IDENTIFIER_KEYWORD_P (value)) + { + keyword = C_RID_CODE (value); + type = CPP_KEYWORD; + } + } + else if (tok->type == CPP_HEADER_NAME) + value = build_string (tok->val.str.len, (const char *)tok->val.str.text); + + return module_token_lang (type, keyword, value, tok->src_loc, data_); +} /* Parse a #pragma whose sole argument is a string constant. If OPT is true, the argument is optional. */ @@ -806,6 +1006,12 @@ cxx_dup_lang_specific_decl (tree node) memcpy (ld, DECL_LANG_SPECIFIC (node), size); DECL_LANG_SPECIFIC (node) = ld; + /* Directly clear some flags that do not apply to the copy + (module_purview_p still does). */ + ld->u.base.module_entity_p = false; + ld->u.base.module_import_p = false; + ld->u.base.module_pending_p = false; + if (GATHER_STATISTICS) { tree_node_counts[(int)lang_decl] += 1; diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc index 5592680..142457e 100644 --- a/gcc/cp/logic.cc +++ b/gcc/cp/logic.cc @@ -1,5 +1,5 @@ /* Derivation and subsumption rules for constraints. - Copyright (C) 2013-2020 Free Software Foundation, Inc. + Copyright (C) 2013-2021 Free Software Foundation, Inc. Contributed by Andrew Sutton (andrew.n.sutton@gmail.com) This file is part of GCC. diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 5548e51..0a9e5aa 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1,5 +1,5 @@ /* Name mangling for the 3.0 -*- C++ -*- ABI. - Copyright (C) 2000-2020 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. Written by Alex Samuel <samuel@codesourcery.com> This file is part of GCC. @@ -117,6 +117,9 @@ struct GTY(()) globals { /* True if the mangling will be different in C++17 mode. */ bool need_cxx17_warning; + + /* True if we mangled a module name. */ + bool mod; }; static GTY (()) globals G; @@ -832,6 +835,62 @@ write_encoding (const tree decl) } } +/* Interface to substitution and identifer mangling, used by the + module name mangler. */ + +void +mangle_module_substitution (int v) +{ + if (v < 10) + { + write_char ('_'); + write_char ('0' + v); + } + else + { + write_char ('W'); + write_unsigned_number (v - 10); + write_char ('_'); + } +} + +void +mangle_identifier (char c, tree id) +{ + if (c) + write_char (c); + write_source_name (id); +} + +/* If the outermost non-namespace context (including DECL itself) is + a module-linkage decl, mangle the module information. For module + global initializers we need to include the partition part. + + <module-name> ::= W <module-id>+ E + <module-id> :: <unqualified-name> + || _ <digit> ;; short backref + || W <number> _ ;; long backref + || P <module-id> ;; partition introducer +*/ + +static void +write_module (int m, bool include_partition) +{ + G.mod = true; + + write_char ('W'); + mangle_module (m, include_partition); + write_char ('E'); +} + +static void +maybe_write_module (tree decl) +{ + int m = get_originating_module (decl, true); + if (m >= 0) + write_module (m, false); +} + /* Lambdas can have a bit more context for mangling, specifically VAR_DECL or PARM_DECL context, which doesn't belong in DECL_CONTEXT. */ @@ -894,6 +953,9 @@ write_name (tree decl, const int ignore_local_scope) decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); } + if (modules_p ()) + maybe_write_module (decl); + context = decl_mangling_context (decl); gcc_assert (context != NULL_TREE); @@ -2806,16 +2868,20 @@ write_member_name (tree member) { if (identifier_p (member)) { - if (abi_version_at_least (11) && IDENTIFIER_ANY_OP_P (member)) + if (IDENTIFIER_ANY_OP_P (member)) { - write_string ("on"); + if (abi_version_at_least (11)) + write_string ("on"); if (abi_warn_or_compat_version_crosses (11)) G.need_abi_warning = 1; } write_unqualified_id (member); } else if (DECL_P (member)) - write_unqualified_name (member); + { + gcc_assert (!DECL_OVERLOADED_OPERATOR_P (member)); + write_unqualified_name (member); + } else if (TREE_CODE (member) == TEMPLATE_ID_EXPR) { tree name = TREE_OPERAND (member, 0); @@ -3100,6 +3166,7 @@ write_expression (tree expr) write_expression (member); else { + gcc_assert (code != BASELINK || BASELINK_QUALIFIED_P (expr)); write_string ("sr"); write_type (scope); write_member_name (member); @@ -3282,7 +3349,15 @@ write_expression (tree expr) } else if (dependent_name (expr)) { - write_unqualified_id (dependent_name (expr)); + tree name = dependent_name (expr); + if (IDENTIFIER_ANY_OP_P (name)) + { + if (abi_version_at_least (15)) + write_string ("on"); + if (abi_warn_or_compat_version_crosses (15)) + G.need_abi_warning = 1; + } + write_unqualified_id (name); } else { @@ -3825,14 +3900,13 @@ start_mangling (const tree entity) G.entity = entity; G.need_abi_warning = false; G.need_cxx17_warning = false; + G.mod = false; obstack_free (&name_obstack, name_base); mangle_obstack = &name_obstack; name_base = obstack_alloc (&name_obstack, 0); } -/* Done with mangling. If WARN is true, and the name of G.entity will - be mangled differently in a future version of the ABI, issue a - warning. */ +/* Done with mangling. Release the data. */ static void finish_mangling_internal (void) @@ -3840,6 +3914,9 @@ finish_mangling_internal (void) /* Clear all the substitutions. */ vec_safe_truncate (G.substitutions, 0); + if (G.mod) + mangle_module_fini (); + /* Null-terminate the string. */ write_char ('\0'); } @@ -3884,6 +3961,20 @@ init_mangle (void) subst_identifiers[SUBID_BASIC_IOSTREAM] = get_identifier ("basic_iostream"); } +/* Generate a mangling for MODULE's global initializer fn. */ + +tree +mangle_module_global_init (int module) +{ + start_mangling (NULL_TREE); + + write_string ("_ZGI"); + write_module (module, true); + write_char ('v'); + + return finish_mangling_get_identifier (); +} + /* Generate the mangled name of DECL. */ static tree diff --git a/gcc/cp/mapper-client.cc b/gcc/cp/mapper-client.cc new file mode 100644 index 0000000..a72b4b7 --- /dev/null +++ b/gcc/cp/mapper-client.cc @@ -0,0 +1,373 @@ +/* C++ modules. Experimental! + Copyright (C) 2017-2021 Free Software Foundation, Inc. + Written by Nathan Sidwell <nathan@acm.org> while at FaceBook + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#if defined (__unix__) +// Solaris11's socket header used bcopy, which we poison. cody.hh +// will include it later under the above check +#include <sys/socket.h> +#endif +#define INCLUDE_STRING +#define INCLUDE_VECTOR +#include "system.h" + +#include "line-map.h" +#include "diagnostic-core.h" +#include "mapper-client.h" +#include "intl.h" + +#include "../../c++tools/resolver.h" + +#if !HOST_HAS_O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +module_client::module_client (pex_obj *p, int fd_from, int fd_to) + : Client (fd_from, fd_to), pex (p) +{ +} + +static module_client * +spawn_mapper_program (char const **errmsg, std::string &name, + char const *full_program_name) +{ + /* Split writable at white-space. No space-containing args for + you! */ + // At most every other char could be an argument + char **argv = new char *[name.size () / 2 + 2]; + unsigned arg_no = 0; + char *str = new char[name.size ()]; + memcpy (str, name.c_str () + 1, name.size ()); + + for (auto ptr = str; ; ++ptr) + { + while (*ptr == ' ') + ptr++; + if (!*ptr) + break; + + if (!arg_no) + { + /* @name means look in the compiler's install dir. */ + if (ptr[0] == '@') + ptr++; + else + full_program_name = nullptr; + } + + argv[arg_no++] = ptr; + while (*ptr && *ptr != ' ') + ptr++; + if (!*ptr) + break; + *ptr = 0; + } + argv[arg_no] = nullptr; + + auto *pex = pex_init (PEX_USE_PIPES, progname, NULL); + FILE *to = pex_input_pipe (pex, false); + name = argv[0]; + if (!to) + *errmsg = "connecting input"; + else + { + int flags = PEX_SEARCH; + + if (full_program_name) + { + /* Prepend the invoking path, if the mapper is a simple + file name. */ + size_t dir_len = progname - full_program_name; + std::string argv0; + argv0.reserve (dir_len + name.size ()); + argv0.append (full_program_name, dir_len).append (name); + name = std::move (argv0); + argv[0] = const_cast <char *> (name.c_str ()); + flags = 0; + } + int err; + *errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err); + } + delete[] str; + delete[] argv; + + int fd_from = -1, fd_to = -1; + if (!*errmsg) + { + FILE *from = pex_read_output (pex, false); + if (from && (fd_to = dup (fileno (to))) >= 0) + fd_from = fileno (from); + else + *errmsg = "connecting output"; + fclose (to); + } + + if (*errmsg) + { + pex_free (pex); + return nullptr; + } + + return new module_client (pex, fd_from, fd_to); +} + +module_client * +module_client::open_module_client (location_t loc, const char *o, + void (*set_repo) (const char *), + char const *full_program_name) +{ + module_client *c = nullptr; + std::string ident; + std::string name; + char const *errmsg = nullptr; + unsigned line = 0; + + if (o && o[0]) + { + /* Maybe a local or ipv6 address. */ + name = o; + auto last = name.find_last_of ('?'); + if (last != name.npos) + { + ident = name.substr (last + 1); + name.erase (last); + } + + if (name.size ()) + { + switch (name[0]) + { + case '<': + // <from>to or <>fromto, or <> + { + size_t pos = name.find ('>', 1); + if (pos == std::string::npos) + pos = name.size (); + std::string from (name, 1, pos - 1); + std::string to; + if (pos != name.size ()) + to.append (name, pos + 1, std::string::npos); + + int fd_from = -1, fd_to = -1; + if (from.empty () && to.empty ()) + { + fd_from = fileno (stdin); + fd_to = fileno (stdout); + } + else + { + char *ptr; + if (!from.empty ()) + { + /* Sadly str::stoul is not portable. */ + const char *cstr = from.c_str (); + fd_from = strtoul (cstr, &ptr, 10); + if (*ptr) + { + /* Not a number -- a named pipe. */ + int dir = to.empty () + ? O_RDWR | O_CLOEXEC : O_RDONLY | O_CLOEXEC; + fd_from = open (cstr, dir); + } + if (to.empty ()) + fd_to = fd_from; + } + + if (!from.empty () && fd_from < 0) + ; + else if (to.empty ()) + ; + else + { + const char *cstr = to.c_str (); + fd_to = strtoul (cstr, &ptr, 10); + if (*ptr) + { + /* Not a number, a named pipe. */ + int dir = from.empty () + ? O_RDWR | O_CLOEXEC : O_WRONLY | O_CLOEXEC; + fd_to = open (cstr, dir); + if (fd_to < 0) + close (fd_from); + } + if (from.empty ()) + fd_from = fd_to; + } + } + + if (fd_from < 0 || fd_to < 0) + errmsg = "opening"; + else + c = new module_client (fd_from, fd_to); + } + break; + + case '=': + // =localsocket + { + int fd = -1; +#if CODY_NETWORKING + fd = Cody::OpenLocal (&errmsg, name.c_str () + 1); +#endif + if (fd >= 0) + c = new module_client (fd, fd); + } + break; + + case '|': + // |program and args + c = spawn_mapper_program (&errmsg, name, full_program_name); + break; + + default: + // file or hostname:port + { + auto colon = name.find_last_of (':'); + if (colon != name.npos) + { + char const *cptr = name.c_str () + colon; + char *endp; + unsigned port = strtoul (cptr + 1, &endp, 10); + + if (port && endp != cptr + 1 && !*endp) + { + name[colon] = 0; + int fd = 01; +#if CODY_NETWORKING + fd = Cody::OpenInet6 (&errmsg, name.c_str (), port); +#endif + name[colon] = ':'; + + if (fd >= 0) + c = new module_client (fd, fd); + } + } + + } + break; + } + } + } + + if (!c) + { + // Make a default in-process client + bool file = !errmsg && !name.empty (); + auto r = new module_resolver (!file, true); + + if (file) + { + int fd = open (name.c_str (), O_RDONLY | O_CLOEXEC); + if (fd < 0) + errmsg = "opening"; + else + { + if (int l = r->read_tuple_file (fd, ident, false)) + { + if (l > 0) + line = l; + errmsg = "reading"; + } + + close (fd); + } + } + else + r->set_repo ("gcm.cache"); + + auto *s = new Cody::Server (r); + c = new module_client (s); + } + +#ifdef SIGPIPE + if (!c->IsDirect ()) + /* We need to ignore sig pipe for a while. */ + c->sigpipe = signal (SIGPIPE, SIG_IGN); +#endif + + if (errmsg) + error_at (loc, line ? G_("failed %s mapper %qs line %u") + : G_("failed %s mapper %qs"), errmsg, name.c_str (), line); + + // now wave hello! + c->Cork (); + c->Connect (std::string ("GCC"), ident); + c->ModuleRepo (); + auto packets = c->Uncork (); + + auto &connect = packets[0]; + if (connect.GetCode () == Cody::Client::PC_CONNECT) + c->flags = Cody::Flags (connect.GetInteger ()); + else if (connect.GetCode () == Cody::Client::PC_ERROR) + error_at (loc, "failed mapper handshake %s", connect.GetString ().c_str ()); + + auto &repo = packets[1]; + if (repo.GetCode () == Cody::Client::PC_PATHNAME) + set_repo (repo.GetString ().c_str ()); + + return c; +} + +void +module_client::close_module_client (location_t loc, module_client *mapper) +{ + if (mapper->IsDirect ()) + { + auto *s = mapper->GetServer (); + auto *r = s->GetResolver (); + delete s; + delete r; + } + else + { + if (mapper->pex) + { + int fd_write = mapper->GetFDWrite (); + if (fd_write >= 0) + close (fd_write); + + int status; + pex_get_status (mapper->pex, 1, &status); + + pex_free (mapper->pex); + mapper->pex = NULL; + + if (WIFSIGNALED (status)) + error_at (loc, "mapper died by signal %s", + strsignal (WTERMSIG (status))); + else if (WIFEXITED (status) && WEXITSTATUS (status) != 0) + error_at (loc, "mapper exit status %d", + WEXITSTATUS (status)); + } + else + { + int fd_read = mapper->GetFDRead (); + close (fd_read); + } + +#ifdef SIGPIPE + // Restore sigpipe + if (mapper->sigpipe != SIG_IGN) + signal (SIGPIPE, mapper->sigpipe); +#endif + } + + delete mapper; +} diff --git a/gcc/cp/mapper-client.h b/gcc/cp/mapper-client.h new file mode 100644 index 0000000..1983081 --- /dev/null +++ b/gcc/cp/mapper-client.h @@ -0,0 +1,63 @@ +/* C++ modules. Experimental! -*- c++ -*- + Copyright (C) 2020-2021 Free Software Foundation, Inc. + Written by Nathan Sidwell <nathan@acm.org> while at FaceBook + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Forward to the header in c++tools. */ + +#ifndef MAPPER_CLIENT_H +#define MAPPER_CLIENT_H 1 + +#include "cody.hh" + +#ifndef HAVE_SIGHANDLER_T +typedef void (*sighandler_t) (int); +#endif + +class module_client : public Cody::Client +{ + pex_obj *pex = nullptr; + sighandler_t sigpipe = SIG_IGN; + Cody::Flags flags = Cody::Flags::None; + +public: + module_client (Cody::Server *s) + : Client (s) + { + } + module_client (pex_obj *pex, int fd_from, int fd_to); + + module_client (int fd_from, int fd_to) + : Client (fd_from, fd_to) + { + } + +public: + Cody::Flags get_flags () const + { + return flags; + } + +public: + static module_client *open_module_client (location_t loc, const char *option, + void (*set_repo) (const char *), + char const *); + static void close_module_client (location_t loc, module_client *); +}; + +#endif diff --git a/gcc/cp/mapper-resolver.cc b/gcc/cp/mapper-resolver.cc new file mode 100644 index 0000000..bcf6c88 --- /dev/null +++ b/gcc/cp/mapper-resolver.cc @@ -0,0 +1,31 @@ +/* C++ modules. Experimental! -*- c++ -*- + Copyright (C) 2020-2021 Free Software Foundation, Inc. + Written by Nathan Sidwell <nathan@acm.org> while at FaceBook + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Forward to the resolver in c++tools. */ + +#include "config.h" +#define INCLUDE_STRING +#define INCLUDE_VECTOR +#define INCLUDE_ALGORITHM +#include "system.h" + +// We don't want or need to be aware of networking +#define CODY_NETWORKING 0 +#include "../../c++tools/resolver.cc" diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 4de192f..3fe3bd8 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1,6 +1,6 @@ /* Handle the hair of processing (but not expanding) inline functions. Also manage function and variable name overloading. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -1063,43 +1063,60 @@ spaceship_type (tree optype, tsubst_flags_t complain) return lookup_comparison_category (tag, complain); } -/* Turn <=> with type TYPE and operands OP0 and OP1 into GENERIC. */ +/* Turn <=> with type TYPE and operands OP0 and OP1 into GENERIC. + This is also used by build_comparison_op for fallback to op< and op== + in a defaulted op<=>. */ tree -genericize_spaceship (tree type, tree op0, tree op1) +genericize_spaceship (location_t loc, tree type, tree op0, tree op1) { /* ??? maybe optimize based on knowledge of representation? */ comp_cat_tag tag = cat_tag_for (type); + + if (tag == cc_last && is_auto (type)) + { + /* build_comparison_op is checking to see if we want to suggest changing + the op<=> return type from auto to a specific comparison category; any + category will do for now. */ + tag = cc_strong_ordering; + type = lookup_comparison_category (tag, tf_none); + if (type == error_mark_node) + return error_mark_node; + } + gcc_checking_assert (tag < cc_last); tree r; - op0 = save_expr (op0); - op1 = save_expr (op1); + if (SCALAR_TYPE_P (TREE_TYPE (op0))) + { + op0 = save_expr (op0); + op1 = save_expr (op1); + } tree gt = lookup_comparison_result (tag, type, 1); + int flags = LOOKUP_NORMAL; + tsubst_flags_t complain = tf_none; + if (tag == cc_partial_ordering) { /* op0 == op1 ? equivalent : op0 < op1 ? less : - op0 > op1 ? greater : unordered */ + op1 < op0 ? greater : unordered */ tree uo = lookup_comparison_result (tag, type, 3); - tree comp = fold_build2 (GT_EXPR, boolean_type_node, op0, op1); - r = fold_build3 (COND_EXPR, type, comp, gt, uo); + tree comp = build_new_op (loc, LT_EXPR, flags, op1, op0, complain); + r = build_conditional_expr (loc, comp, gt, uo, complain); } else /* op0 == op1 ? equal : op0 < op1 ? less : greater */ r = gt; tree lt = lookup_comparison_result (tag, type, 2); - tree comp = fold_build2 (LT_EXPR, boolean_type_node, op0, op1); - r = fold_build3 (COND_EXPR, type, comp, lt, r); + tree comp = build_new_op (loc, LT_EXPR, flags, op0, op1, complain); + r = build_conditional_expr (loc, comp, lt, r, complain); tree eq = lookup_comparison_result (tag, type, 0); - comp = fold_build2 (EQ_EXPR, boolean_type_node, op0, op1); - r = fold_build3 (COND_EXPR, type, comp, eq, r); - - /* Wrap the whole thing in a TARGET_EXPR like build_conditional_expr_1. */ - r = get_target_expr (r); + comp = build_new_op (loc, EQ_EXPR, flags, op0, op1, complain); + r = build_conditional_expr (loc, comp, eq, r, complain); return r; } @@ -1213,6 +1230,8 @@ common_comparison_type (vec<tree> &comps) for (unsigned i = 0; i < comps.length(); ++i) { tree comp = comps[i]; + if (TREE_CODE (comp) == TREE_LIST) + comp = TREE_VALUE (comp); tree ctype = TREE_TYPE (comp); comp_cat_tag tag = cat_tag_for (ctype); /* build_comparison_op already checked this. */ @@ -1323,7 +1342,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) if (!info.defining && !(complain & tf_error) && !DECL_MAYBE_DELETED (fndecl)) return; - int flags = LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED; + int flags = LOOKUP_NORMAL; const ovl_op_info_t *op = IDENTIFIER_OVL_OP_INFO (DECL_NAME (fndecl)); tree_code code = op->tree_code; @@ -1364,6 +1383,10 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) if (code == EQ_EXPR || code == SPACESHIP_EXPR) { + comp_cat_tag retcat = cc_last; + if (code == SPACESHIP_EXPR && !FNDECL_USED_AUTO (fndecl)) + retcat = cat_tag_for (rettype); + bool bad = false; auto_vec<tree> comps; @@ -1375,13 +1398,15 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) { tree expr_type = TREE_TYPE (field); + location_t field_loc = DECL_SOURCE_LOCATION (field); + /* A defaulted comparison operator function for class C is defined as deleted if any non-static data member of C is of reference type or C has variant members. */ if (TREE_CODE (expr_type) == REFERENCE_TYPE) { if (complain & tf_error) - inform (DECL_SOURCE_LOCATION (field), "cannot default compare " + inform (field_loc, "cannot default compare " "reference member %qD", field); bad = true; continue; @@ -1390,35 +1415,128 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) && next_initializable_field (TYPE_FIELDS (expr_type))) { if (complain & tf_error) - inform (DECL_SOURCE_LOCATION (field), "cannot default compare " + inform (field_loc, "cannot default compare " "anonymous union member"); bad = true; continue; } - tree lhs_mem = build3 (COMPONENT_REF, expr_type, lhs, field, - NULL_TREE); - tree rhs_mem = build3 (COMPONENT_REF, expr_type, rhs, field, - NULL_TREE); - tree comp = build_new_op (info.loc, code, flags, lhs_mem, rhs_mem, - NULL_TREE, NULL, complain); + tree lhs_mem = build3_loc (field_loc, COMPONENT_REF, expr_type, lhs, + field, NULL_TREE); + tree rhs_mem = build3_loc (field_loc, COMPONENT_REF, expr_type, rhs, + field, NULL_TREE); + tree loop_indexes = NULL_TREE; + while (TREE_CODE (expr_type) == ARRAY_TYPE) + { + /* Flexible array member. */ + if (TYPE_DOMAIN (expr_type) == NULL_TREE + || TYPE_MAX_VALUE (TYPE_DOMAIN (expr_type)) == NULL_TREE) + { + if (complain & tf_error) + inform (field_loc, "cannot default compare " + "flexible array member"); + bad = true; + break; + } + tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (expr_type)); + /* [0] array. No subobjects to compare, just skip it. */ + if (integer_all_onesp (maxval)) + break; + tree idx; + /* [1] array, no loop needed, just add [0] ARRAY_REF. + Similarly if !info.defining. */ + if (integer_zerop (maxval) || !info.defining) + idx = size_zero_node; + /* Some other array, will need runtime loop. */ + else + { + idx = force_target_expr (sizetype, maxval, complain); + loop_indexes = tree_cons (idx, NULL_TREE, loop_indexes); + } + expr_type = TREE_TYPE (expr_type); + lhs_mem = build4_loc (field_loc, ARRAY_REF, expr_type, lhs_mem, + idx, NULL_TREE, NULL_TREE); + rhs_mem = build4_loc (field_loc, ARRAY_REF, expr_type, rhs_mem, + idx, NULL_TREE, NULL_TREE); + } + if (TREE_CODE (expr_type) == ARRAY_TYPE) + continue; + + tree overload = NULL_TREE; + tree comp = build_new_op (field_loc, code, flags, lhs_mem, rhs_mem, + NULL_TREE, &overload, + retcat != cc_last ? tf_none : complain); if (comp == error_mark_node) { - bad = true; - continue; + if (overload == NULL_TREE && code == SPACESHIP_EXPR + && (retcat != cc_last || complain)) + { + tree comptype = (retcat != cc_last ? rettype + : DECL_SAVED_AUTO_RETURN_TYPE (fndecl)); + /* No viable <=>, try using op< and op==. */ + tree lteq = genericize_spaceship (field_loc, comptype, + lhs_mem, rhs_mem); + if (lteq != error_mark_node) + { + /* We found usable < and ==. */ + if (retcat != cc_last) + /* Return type is a comparison category, use them. */ + comp = lteq; + else if (complain & tf_error) + /* Return type is auto, suggest changing it. */ + inform (info.loc, "changing the return type from %qs " + "to a comparison category type will allow the " + "comparison to use %qs and %qs", "auto", + "operator<", "operator=="); + } + else if (retcat != cc_last && complain != tf_none) + /* No usable < and ==, give an error for op<=>. */ + build_new_op (field_loc, code, flags, lhs_mem, rhs_mem, + complain); + } + if (comp == error_mark_node) + { + bad = true; + continue; + } } - if (code == SPACESHIP_EXPR - && cat_tag_for (TREE_TYPE (comp)) == cc_last) + if (code != SPACESHIP_EXPR) + ; + else if (FNDECL_USED_AUTO (fndecl) + && cat_tag_for (TREE_TYPE (comp)) == cc_last) { /* The operator function is defined as deleted if ... Ri is not a comparison category type. */ if (complain & tf_error) - inform (DECL_SOURCE_LOCATION (field), + inform (field_loc, "three-way comparison of %qD has type %qT, not a " "comparison category type", field, TREE_TYPE (comp)); bad = true; continue; } + else if (!FNDECL_USED_AUTO (fndecl) + && !can_convert (rettype, TREE_TYPE (comp), complain)) + { + if (complain & tf_error) + error_at (field_loc, + "three-way comparison of %qD has type %qT, which " + "does not convert to %qT", + field, TREE_TYPE (comp), rettype); + bad = true; + continue; + } + /* Most of the time, comp is the expression that should be evaluated + to compare the two members. If the expression needs to be + evaluated more than once in a loop, it will be a TREE_LIST + instead, whose TREE_VALUE is the expression for one array element, + TREE_PURPOSE is innermost iterator temporary and if the array + is multidimensional, TREE_CHAIN will contain another TREE_LIST + with second innermost iterator in its TREE_PURPOSE and so on. */ + if (loop_indexes) + { + TREE_VALUE (loop_indexes) = comp; + comp = loop_indexes; + } comps.safe_push (comp); } if (code == SPACESHIP_EXPR && is_auto (rettype)) @@ -1435,8 +1553,38 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) { tree comp = comps[i]; tree eq, retval = NULL_TREE, if_ = NULL_TREE; + tree loop_indexes = NULL_TREE; if (info.defining) - if_ = begin_if_stmt (); + { + if (TREE_CODE (comp) == TREE_LIST) + { + loop_indexes = comp; + comp = TREE_VALUE (comp); + loop_indexes = nreverse (loop_indexes); + for (tree loop_index = loop_indexes; loop_index; + loop_index = TREE_CHAIN (loop_index)) + { + tree for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE); + tree idx = TREE_PURPOSE (loop_index); + tree maxval = TARGET_EXPR_INITIAL (idx); + TARGET_EXPR_INITIAL (idx) = size_zero_node; + add_stmt (idx); + finish_init_stmt (for_stmt); + finish_for_cond (build2 (LE_EXPR, boolean_type_node, idx, + maxval), for_stmt, false, 0); + finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR, + TARGET_EXPR_SLOT (idx), + false, complain), + for_stmt); + /* Store in TREE_VALUE the for_stmt tree, so that we can + later on call finish_for_stmt on it (in the reverse + order). */ + TREE_VALUE (loop_index) = for_stmt; + } + loop_indexes = nreverse (loop_indexes); + } + if_ = begin_if_stmt (); + } /* Spaceship is specified to use !=, but for the comparison category types, != is equivalent to !(==), so let's use == directly. */ if (code == EQ_EXPR) @@ -1475,6 +1623,9 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) finish_return_stmt (retval); finish_else_clause (if_); finish_if_stmt (if_); + for (tree loop_index = loop_indexes; loop_index; + loop_index = TREE_CHAIN (loop_index)) + finish_for_stmt (TREE_VALUE (loop_index)); } } if (info.defining) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 596061b..41ce201 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -1,5 +1,5 @@ /* C++ modules. Experimental! - Copyright (C) 2017-2020 Free Software Foundation, Inc. + Copyright (C) 2017-2021 Free Software Foundation, Inc. Written by Nathan Sidwell <nathan@acm.org> while at FaceBook This file is part of GCC. @@ -18,4 +18,19961 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -/* This file intentionally left empty. */ +/* Comments in this file have a non-negligible chance of being wrong + or at least inaccurate. Due to (a) my misunderstanding, (b) + ambiguities that I have interpretted differently to original intent + (c) changes in the specification, (d) my poor wording, (e) source + changes. */ + +/* (Incomplete) Design Notes + + A hash table contains all module names. Imported modules are + present in a modules array, which by construction places an + import's dependencies before the import itself. The single + exception is the current TU, which always occupies slot zero (even + when it is not a module). + + Imported decls occupy an entity_ary, an array of binding_slots, indexed + by importing module and index within that module. A flat index is + used, as each module reserves a contiguous range of indices. + Initially each slot indicates the CMI section containing the + streamed decl. When the decl is imported it will point to the decl + itself. + + Additionally each imported decl is mapped in the entity_map via its + DECL_UID to the flat index in the entity_ary. Thus we can locate + the index for any imported decl by using this map and then + de-flattening the index via a binary seach of the module vector. + Cross-module references are by (remapped) module number and + module-local index. + + Each importable DECL contains several flags. The simple set are + DECL_EXPORT_P, DECL_MODULE_PURVIEW_P and DECL_MODULE_IMPORT_P. The + first indicates whether it is exported, the second whether it is in + the module purview (as opposed to the global module fragment), and + the third indicates whether it was an import into this TU or not. + + The more detailed flags are DECL_MODULE_PARTITION_P, + DECL_MODULE_ENTITY_P & DECL_MODULE_PENDING_SPECIALIZATIONS_P. The + first is set in a primary interface unit on decls that were read + from module partitions (these will have DECL_MODULE_IMPORT_P set + too). Such decls will be streamed out to the primary's CMI. + DECL_MODULE_ENTITY_P is set when an entity is imported, even if it + matched a non-imported entity. Such a decl will not have + DECL_MODULE_IMPORT_P set, even though it has an entry in the entity + map and array. DECL_MODULE_PENDING_SPECIALIZATIONS_P is set on a + primary template, and indicates there are specializations that + should be streamed in before trying to specialize this template. + + Header units are module-like. + + For namespace-scope lookup, the decls for a particular module are + held located in a sparse array hanging off the binding of the name. + This is partitioned into two: a few fixed slots at the start + followed by the sparse slots afterwards. By construction we only + need to append new slots to the end -- there is never a need to + insert in the middle. The fixed slots are MODULE_SLOT_CURRENT for + the current TU (regardless of whether it is a module or not), + MODULE_SLOT_GLOBAL and MODULE_SLOT_PARTITION. These latter two + slots are used for merging entities across the global module and + module partitions respectively. MODULE_SLOT_PARTITION is only + present in a module. Neither of those two slots is searched during + name lookup -- they are internal use only. This vector is created + lazily once we require it, if there is only a declaration from the + current TU, a regular binding is present. It is converted on + demand. + + OPTIMIZATION: Outside of the current TU, we only need ADL to work. + We could optimize regular lookup for the current TU by glomming all + the visible decls on its slot. Perhaps wait until design is a + little more settled though. + + There is only one instance of each extern-linkage namespace. It + appears in every module slot that makes it visible. It also + appears in MODULE_SLOT_GLOBAL. (It is an ODR violation if they + collide with some other global module entity.) We also have an + optimization that shares the slot for adjacent modules that declare + the same such namespace. + + A module interface compilation produces a Compiled Module Interface + (CMI). The format used is Encapsulated Lazy Records Of Numbered + Declarations, which is essentially ELF's section encapsulation. (As + all good nerds are aware, Elrond is half Elf.) Some sections are + named, and contain information about the module as a whole (indices + etc), and other sections are referenced by number. Although I + don't defend against actively hostile CMIs, there is some + checksumming involved to verify data integrity. When dumping out + an interface, we generate a graph of all the + independently-redeclarable DECLS that are needed, and the decls + they reference. From that we determine the strongly connected + components (SCC) within this TU. Each SCC is dumped to a separate + numbered section of the CMI. We generate a binding table section, + mapping each namespace&name to a defining section. This allows + lazy loading. + + Lazy loading employs mmap to map a read-only image of the CMI. + It thus only occupies address space and is paged in on demand, + backed by the CMI file itself. If mmap is unavailable, regular + FILEIO is used. Also, there's a bespoke ELF reader/writer here, + which implements just the section table and sections (including + string sections) of a 32-bit ELF in host byte-order. You can of + course inspect it with readelf. I figured 32-bit is sufficient, + for a single module. I detect running out of section numbers, but + do not implement the ELF overflow mechanism. At least you'll get + an error if that happens. + + We do not separate declarations and definitions. My guess is that + if you refer to the declaration, you'll also need the definition + (template body, inline function, class definition etc). But this + does mean we can get larger SCCs than if we separated them. It is + unclear whether this is a win or not. + + Notice that we embed section indices into the contents of other + sections. Thus random manipulation of the CMI file by ELF tools + may well break it. The kosher way would probably be to introduce + indirection via section symbols, but that would require defining a + relocation type. + + Notice that lazy loading of one module's decls can cause lazy + loading of other decls in the same or another module. Clearly we + want to avoid loops. In a correct program there can be no loops in + the module dependency graph, and the above-mentioned SCC algorithm + places all intra-module circular dependencies in the same SCC. It + also orders the SCCs wrt each other, so dependent SCCs come first. + As we load dependent modules first, we know there can be no + reference to a higher-numbered module, and because we write out + dependent SCCs first, likewise for SCCs within the module. This + allows us to immediately detect broken references. When loading, + we must ensure the rest of the compiler doesn't cause some + unconnected load to occur (for instance, instantiate a template). + +Classes used: + + dumper - logger + + data - buffer + + bytes - data streamer + bytes_in : bytes - scalar reader + bytes_out : bytes - scalar writer + + elf - ELROND format + elf_in : elf - ELROND reader + elf_out : elf - ELROND writer + + trees_in : bytes_in - tree reader + trees_out : bytes_out - tree writer + + depset - dependency set + depset::hash - hash table of depsets + depset::tarjan - SCC determinator + + uidset<T> - set T's related to a UID + uidset<T>::hash hash table of uidset<T> + + loc_spans - location map data + + module_state - module object + + slurping - data needed during loading + + macro_import - imported macro data + macro_export - exported macro data + + The ELROND objects use mmap, for both reading and writing. If mmap + is unavailable, fileno IO is used to read and write blocks of data. + + The mapper object uses fileno IO to communicate with the server or + program. */ + +/* In expermental (trunk) sources, MODULE_VERSION is a #define passed + in from the Makefile. It records the modification date of the + source directory -- that's the only way to stay sane. In release + sources, we (plan to) use the compiler's major.minor versioning. + While the format might not change between at minor versions, it + seems simplest to tie the two together. There's no concept of + inter-version compatibility. */ +#define IS_EXPERIMENTAL(V) ((V) >= (1U << 20)) +#define MODULE_MAJOR(V) ((V) / 10000) +#define MODULE_MINOR(V) ((V) % 10000) +#define EXPERIMENT(A,B) (IS_EXPERIMENTAL (MODULE_VERSION) ? (A) : (B)) +#ifndef MODULE_VERSION +// Be sure you're ready! Remove #error this before release! +#error "Shtopp! What are you doing? This is not ready yet." +#include "bversion.h" +#define MODULE_VERSION (BUILDING_GCC_MAJOR * 10000U + BUILDING_GCC_MINOR) +#elif !IS_EXPERIMENTAL (MODULE_VERSION) +#error "This is not the version I was looking for." +#endif + +#define _DEFAULT_SOURCE 1 /* To get TZ field of struct tm, if available. */ +#include "config.h" +#define INCLUDE_STRING +#define INCLUDE_VECTOR +#include "system.h" +#include "coretypes.h" +#include "cp-tree.h" +#include "timevar.h" +#include "stringpool.h" +#include "dumpfile.h" +#include "bitmap.h" +#include "cgraph.h" +#include "tree-iterator.h" +#include "cpplib.h" +#include "mkdeps.h" +#include "incpath.h" +#include "libiberty.h" +#include "stor-layout.h" +#include "version.h" +#include "tree-diagnostic.h" +#include "toplev.h" +#include "opts.h" +#include "attribs.h" +#include "intl.h" +#include "langhooks.h" +/* This TU doesn't need or want to see the networking. */ +#define CODY_NETWORKING 0 +#include "mapper-client.h" + +#if 0 // 1 for testing no mmap +#define MAPPED_READING 0 +#define MAPPED_WRITING 0 +#else +#if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0 +/* mmap, munmap. */ +#define MAPPED_READING 1 +#if HAVE_SYSCONF && defined (_SC_PAGE_SIZE) +/* msync, sysconf (_SC_PAGE_SIZE), ftruncate */ +/* posix_fallocate used if available. */ +#define MAPPED_WRITING 1 +#else +#define MAPPED_WRITING 0 +#endif +#else +#define MAPPED_READING 0 +#define MAPPED_WRITING 0 +#endif +#endif + +/* Some open(2) flag differences, what a colourful world it is! */ +#if defined (O_CLOEXEC) +// OK +#elif defined (_O_NOINHERIT) +/* Windows' _O_NOINHERIT matches O_CLOEXEC flag */ +#define O_CLOEXEC _O_NOINHERIT +#else +#define O_CLOEXEC 0 +#endif +#if defined (O_BINARY) +// Ok? +#elif defined (_O_BINARY) +/* Windows' open(2) call defaults to text! */ +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif + +static inline cpp_hashnode *cpp_node (tree id) +{ + return CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (id)); +} + +static inline tree identifier (const cpp_hashnode *node) +{ + return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast<cpp_hashnode *> (node))); +} + +/* During duplicate detection we need to tell some comparators that + these are equivalent. */ +tree map_context_from; +tree map_context_to; + +/* Id for dumping module information. */ +int module_dump_id; + +/* We have a special module owner. */ +#define MODULE_UNKNOWN (~0U) /* Not yet known. */ + +/* Prefix for section names. */ +#define MOD_SNAME_PFX ".gnu.c++" + +/* Format a version for user consumption. */ + +typedef char verstr_t[32]; +static void +version2string (unsigned version, verstr_t &out) +{ + unsigned major = MODULE_MAJOR (version); + unsigned minor = MODULE_MINOR (version); + + if (IS_EXPERIMENTAL (version)) + sprintf (out, "%04u/%02u/%02u-%02u:%02u%s", + 2000 + major / 10000, (major / 100) % 100, (major % 100), + minor / 100, minor % 100, + EXPERIMENT ("", " (experimental)")); + else + sprintf (out, "%u.%u", major, minor); +} + +/* Include files to note translation for. */ +static vec<const char *, va_heap, vl_embed> *note_includes; + +/* Traits to hash an arbitrary pointer. Entries are not deletable, + and removal is a noop (removal needed upon destruction). */ +template <typename T> +struct nodel_ptr_hash : pointer_hash<T>, typed_noop_remove <T *> { + /* Nothing is deletable. Everything is insertable. */ + static bool is_deleted (T *) { return false; } + static void mark_deleted (T *) { gcc_unreachable (); } +}; + +/* Map from pointer to signed integer. */ +typedef simple_hashmap_traits<nodel_ptr_hash<void>, int> ptr_int_traits; +typedef hash_map<void *,signed,ptr_int_traits> ptr_int_hash_map; + +/********************************************************************/ +/* Basic streaming & ELF. Serialization is usually via mmap. For + writing we slide a buffer over the output file, syncing it + approproiately. For reading we simply map the whole file (as a + file-backed read-only map -- it's just address space, leaving the + OS pager to deal with getting the data to us). Some buffers need + to be more conventional malloc'd contents. */ + +/* Variable length buffer. */ + +class data { +public: + class allocator { + public: + /* Tools tend to moan if the dtor's not virtual. */ + virtual ~allocator () {} + + public: + void grow (data &obj, unsigned needed, bool exact); + void shrink (data &obj); + + public: + virtual char *grow (char *ptr, unsigned needed); + virtual void shrink (char *ptr); + }; + +public: + char *buffer; /* Buffer being transferred. */ + /* Although size_t would be the usual size, we know we never get + more than 4GB of buffer -- because that's the limit of the + encapsulation format. And if you need bigger imports, you're + doing it wrong. */ + unsigned size; /* Allocated size of buffer. */ + unsigned pos; /* Position in buffer. */ + +public: + data () + :buffer (NULL), size (0), pos (0) + { + } + ~data () + { + /* Make sure the derived and/or using class know what they're + doing. */ + gcc_checking_assert (!buffer); + } + +protected: + char *use (unsigned count) + { + if (size < pos + count) + return NULL; + char *res = &buffer[pos]; + pos += count; + return res; + } + +public: + void unuse (unsigned count) + { + pos -= count; + } + +public: + static allocator simple_memory; +}; + +/* The simple data allocator. */ +data::allocator data::simple_memory; + +/* Grow buffer to at least size NEEDED. */ + +void +data::allocator::grow (data &obj, unsigned needed, bool exact) +{ + gcc_checking_assert (needed ? needed > obj.size : !obj.size); + if (!needed) + /* Pick a default size. */ + needed = EXPERIMENT (100, 1000); + + if (!exact) + needed *= 2; + obj.buffer = grow (obj.buffer, needed); + if (obj.buffer) + obj.size = needed; + else + obj.pos = obj.size = 0; +} + +/* Free a buffer. */ + +void +data::allocator::shrink (data &obj) +{ + shrink (obj.buffer); + obj.buffer = NULL; + obj.size = 0; +} + +char * +data::allocator::grow (char *ptr, unsigned needed) +{ + return XRESIZEVAR (char, ptr, needed); +} + +void +data::allocator::shrink (char *ptr) +{ + XDELETEVEC (ptr); +} + +/* Byte streamer base. Buffer with read/write position and smarts + for single bits. */ + +class bytes : public data { +public: + typedef data parent; + +protected: + uint32_t bit_val; /* Bit buffer. */ + unsigned bit_pos; /* Next bit in bit buffer. */ + +public: + bytes () + :parent (), bit_val (0), bit_pos (0) + {} + ~bytes () + { + } + +protected: + unsigned calc_crc (unsigned) const; + +protected: + /* Finish bit packet. Rewind the bytes not used. */ + unsigned bit_flush () + { + gcc_assert (bit_pos); + unsigned bytes = (bit_pos + 7) / 8; + unuse (4 - bytes); + bit_pos = 0; + bit_val = 0; + return bytes; + } +}; + +/* Calculate the crc32 of the buffer. Note the CRC is stored in the + first 4 bytes, so don't include them. */ + +unsigned +bytes::calc_crc (unsigned l) const +{ + unsigned crc = 0; + for (size_t ix = 4; ix < l; ix++) + crc = crc32_byte (crc, buffer[ix]); + return crc; +} + +class elf_in; + +/* Byte stream reader. */ + +class bytes_in : public bytes { + typedef bytes parent; + +protected: + bool overrun; /* Sticky read-too-much flag. */ + +public: + bytes_in () + : parent (), overrun (false) + { + } + ~bytes_in () + { + } + +public: + /* Begin reading a named section. */ + bool begin (location_t loc, elf_in *src, const char *name); + /* Begin reading a numbered section with optional name. */ + bool begin (location_t loc, elf_in *src, unsigned, const char * = NULL); + /* Complete reading a buffer. Propagate errors and return true on + success. */ + bool end (elf_in *src); + /* Return true if there is unread data. */ + bool more_p () const + { + return pos != size; + } + +public: + /* Start reading at OFFSET. */ + void random_access (unsigned offset) + { + if (offset > size) + set_overrun (); + pos = offset; + bit_pos = bit_val = 0; + } + +public: + void align (unsigned boundary) + { + if (unsigned pad = pos & (boundary - 1)) + read (boundary - pad); + } + +public: + const char *read (unsigned count) + { + char *ptr = use (count); + if (!ptr) + set_overrun (); + return ptr; + } + +public: + bool check_crc () const; + /* We store the CRC in the first 4 bytes, using host endianness. */ + unsigned get_crc () const + { + return *(const unsigned *)&buffer[0]; + } + +public: + /* Manipulate the overrun flag. */ + bool get_overrun () const + { + return overrun; + } + void set_overrun () + { + overrun = true; + } + +public: + unsigned u32 (); /* Read uncompressed integer. */ + +public: + bool b (); /* Read a bool. */ + void bflush (); /* Completed a block of bools. */ + +private: + void bfill (); /* Get the next block of bools. */ + +public: + int c (); /* Read a char. */ + int i (); /* Read a signed int. */ + unsigned u (); /* Read an unsigned int. */ + size_t z (); /* Read a size_t. */ + HOST_WIDE_INT wi (); /* Read a HOST_WIDE_INT. */ + unsigned HOST_WIDE_INT wu (); /* Read an unsigned HOST_WIDE_INT. */ + const char *str (size_t * = NULL); /* Read a string. */ + const void *buf (size_t); /* Read a fixed-length buffer. */ + cpp_hashnode *cpp_node (); /* Read a cpp node. */ +}; + +/* Verify the buffer's CRC is correct. */ + +bool +bytes_in::check_crc () const +{ + if (size < 4) + return false; + + unsigned c_crc = calc_crc (size); + if (c_crc != get_crc ()) + return false; + + return true; +} + +class elf_out; + +/* Byte stream writer. */ + +class bytes_out : public bytes { + typedef bytes parent; + +public: + allocator *memory; /* Obtainer of memory. */ + +public: + bytes_out (allocator *memory) + : parent (), memory (memory) + { + } + ~bytes_out () + { + } + +public: + bool streaming_p () const + { + return memory != NULL; + } + +public: + void set_crc (unsigned *crc_ptr); + +public: + /* Begin writing, maybe reserve space for CRC. */ + void begin (bool need_crc = true); + /* Finish writing. Spill to section by number. */ + unsigned end (elf_out *, unsigned, unsigned *crc_ptr = NULL); + +public: + void align (unsigned boundary) + { + if (unsigned pad = pos & (boundary - 1)) + write (boundary - pad); + } + +public: + char *write (unsigned count, bool exact = false) + { + if (size < pos + count) + memory->grow (*this, pos + count, exact); + return use (count); + } + +public: + void u32 (unsigned); /* Write uncompressed integer. */ + +public: + void b (bool); /* Write bool. */ + void bflush (); /* Finish block of bools. */ + +public: + void c (unsigned char); /* Write unsigned char. */ + void i (int); /* Write signed int. */ + void u (unsigned); /* Write unsigned int. */ + void z (size_t s); /* Write size_t. */ + void wi (HOST_WIDE_INT); /* Write HOST_WIDE_INT. */ + void wu (unsigned HOST_WIDE_INT); /* Write unsigned HOST_WIDE_INT. */ + void str (const char *ptr) + { + str (ptr, strlen (ptr)); + } + void cpp_node (const cpp_hashnode *node) + { + str ((const char *)NODE_NAME (node), NODE_LEN (node)); + } + void str (const char *, size_t); /* Write string of known length. */ + void buf (const void *, size_t); /* Write fixed length buffer. */ + void *buf (size_t); /* Create a writable buffer */ + +public: + /* Format a NUL-terminated raw string. */ + void printf (const char *, ...) ATTRIBUTE_PRINTF_2; + void print_time (const char *, const tm *, const char *); + +public: + /* Dump instrumentation. */ + static void instrument (); + +protected: + /* Instrumentation. */ + static unsigned spans[4]; + static unsigned lengths[4]; + static int is_set; +}; + +/* Instrumentation. */ +unsigned bytes_out::spans[4]; +unsigned bytes_out::lengths[4]; +int bytes_out::is_set = -1; + +/* If CRC_PTR non-null, set the CRC of the buffer. Mix the CRC into + that pointed to by CRC_PTR. */ + +void +bytes_out::set_crc (unsigned *crc_ptr) +{ + if (crc_ptr) + { + gcc_checking_assert (pos >= 4); + + unsigned crc = calc_crc (pos); + unsigned accum = *crc_ptr; + /* Only mix the existing *CRC_PTR if it is non-zero. */ + accum = accum ? crc32_unsigned (accum, crc) : crc; + *crc_ptr = accum; + + /* Buffer will be sufficiently aligned. */ + *(unsigned *)buffer = crc; + } +} + +/* Finish a set of bools. */ + +void +bytes_out::bflush () +{ + if (bit_pos) + { + u32 (bit_val); + lengths[2] += bit_flush (); + } + spans[2]++; + is_set = -1; +} + +void +bytes_in::bflush () +{ + if (bit_pos) + bit_flush (); +} + +/* When reading, we don't know how many bools we'll read in. So read + 4 bytes-worth, and then rewind when flushing if we didn't need them + all. You can't have a block of bools closer than 4 bytes to the + end of the buffer. */ + +void +bytes_in::bfill () +{ + bit_val = u32 (); +} + +/* Bools are packed into bytes. You cannot mix bools and non-bools. + You must call bflush before emitting another type. So batch your + bools. + + It may be worth optimizing for most bools being zero. Some kind of + run-length encoding? */ + +void +bytes_out::b (bool x) +{ + if (is_set != x) + { + is_set = x; + spans[x]++; + } + lengths[x]++; + bit_val |= unsigned (x) << bit_pos++; + if (bit_pos == 32) + { + u32 (bit_val); + lengths[2] += bit_flush (); + } +} + +bool +bytes_in::b () +{ + if (!bit_pos) + bfill (); + bool v = (bit_val >> bit_pos++) & 1; + if (bit_pos == 32) + bit_flush (); + return v; +} + +/* Exactly 4 bytes. Used internally for bool packing and a few other + places. We can't simply use uint32_t because (a) alignment and + (b) we need little-endian for the bool streaming rewinding to make + sense. */ + +void +bytes_out::u32 (unsigned val) +{ + if (char *ptr = write (4)) + { + ptr[0] = val; + ptr[1] = val >> 8; + ptr[2] = val >> 16; + ptr[3] = val >> 24; + } +} + +unsigned +bytes_in::u32 () +{ + unsigned val = 0; + if (const char *ptr = read (4)) + { + val |= (unsigned char)ptr[0]; + val |= (unsigned char)ptr[1] << 8; + val |= (unsigned char)ptr[2] << 16; + val |= (unsigned char)ptr[3] << 24; + } + + return val; +} + +/* Chars are unsigned and written as single bytes. */ + +void +bytes_out::c (unsigned char v) +{ + if (char *ptr = write (1)) + *ptr = v; +} + +int +bytes_in::c () +{ + int v = 0; + if (const char *ptr = read (1)) + v = (unsigned char)ptr[0]; + return v; +} + +/* Ints 7-bit as a byte. Otherwise a 3bit count of following bytes in + big-endian form. 4 bits are in the first byte. */ + +void +bytes_out::i (int v) +{ + if (char *ptr = write (1)) + { + if (v <= 0x3f && v >= -0x40) + *ptr = v & 0x7f; + else + { + unsigned bytes = 0; + int probe; + if (v >= 0) + for (probe = v >> 8; probe > 0x7; probe >>= 8) + bytes++; + else + for (probe = v >> 8; probe < -0x8; probe >>= 8) + bytes++; + *ptr = 0x80 | bytes << 4 | (probe & 0xf); + if ((ptr = write (++bytes))) + for (; bytes--; v >>= 8) + ptr[bytes] = v & 0xff; + } + } +} + +int +bytes_in::i () +{ + int v = 0; + if (const char *ptr = read (1)) + { + v = *ptr & 0xff; + if (v & 0x80) + { + unsigned bytes = (v >> 4) & 0x7; + v &= 0xf; + if (v & 0x8) + v |= -1 ^ 0x7; + /* unsigned necessary due to left shifts of -ve values. */ + unsigned uv = unsigned (v); + if ((ptr = read (++bytes))) + while (bytes--) + uv = (uv << 8) | (*ptr++ & 0xff); + v = int (uv); + } + else if (v & 0x40) + v |= -1 ^ 0x3f; + } + + return v; +} + +void +bytes_out::u (unsigned v) +{ + if (char *ptr = write (1)) + { + if (v <= 0x7f) + *ptr = v; + else + { + unsigned bytes = 0; + unsigned probe; + for (probe = v >> 8; probe > 0xf; probe >>= 8) + bytes++; + *ptr = 0x80 | bytes << 4 | probe; + if ((ptr = write (++bytes))) + for (; bytes--; v >>= 8) + ptr[bytes] = v & 0xff; + } + } +} + +unsigned +bytes_in::u () +{ + unsigned v = 0; + + if (const char *ptr = read (1)) + { + v = *ptr & 0xff; + if (v & 0x80) + { + unsigned bytes = (v >> 4) & 0x7; + v &= 0xf; + if ((ptr = read (++bytes))) + while (bytes--) + v = (v << 8) | (*ptr++ & 0xff); + } + } + + return v; +} + +void +bytes_out::wi (HOST_WIDE_INT v) +{ + if (char *ptr = write (1)) + { + if (v <= 0x3f && v >= -0x40) + *ptr = v & 0x7f; + else + { + unsigned bytes = 0; + HOST_WIDE_INT probe; + if (v >= 0) + for (probe = v >> 8; probe > 0x7; probe >>= 8) + bytes++; + else + for (probe = v >> 8; probe < -0x8; probe >>= 8) + bytes++; + *ptr = 0x80 | bytes << 4 | (probe & 0xf); + if ((ptr = write (++bytes))) + for (; bytes--; v >>= 8) + ptr[bytes] = v & 0xff; + } + } +} + +HOST_WIDE_INT +bytes_in::wi () +{ + HOST_WIDE_INT v = 0; + if (const char *ptr = read (1)) + { + v = *ptr & 0xff; + if (v & 0x80) + { + unsigned bytes = (v >> 4) & 0x7; + v &= 0xf; + if (v & 0x8) + v |= -1 ^ 0x7; + /* unsigned necessary due to left shifts of -ve values. */ + unsigned HOST_WIDE_INT uv = (unsigned HOST_WIDE_INT) v; + if ((ptr = read (++bytes))) + while (bytes--) + uv = (uv << 8) | (*ptr++ & 0xff); + v = (HOST_WIDE_INT) uv; + } + else if (v & 0x40) + v |= -1 ^ 0x3f; + } + + return v; +} + +/* unsigned wide ints are just written as signed wide ints. */ + +inline void +bytes_out::wu (unsigned HOST_WIDE_INT v) +{ + wi ((HOST_WIDE_INT) v); +} + +inline unsigned HOST_WIDE_INT +bytes_in::wu () +{ + return (unsigned HOST_WIDE_INT) wi (); +} + +/* size_t written as unsigned or unsigned wide int. */ + +inline void +bytes_out::z (size_t s) +{ + if (sizeof (s) == sizeof (unsigned)) + u (s); + else + wu (s); +} + +inline size_t +bytes_in::z () +{ + if (sizeof (size_t) == sizeof (unsigned)) + return u (); + else + return wu (); +} + +/* Buffer simply memcpied. */ +void * +bytes_out::buf (size_t len) +{ + align (sizeof (void *) * 2); + return write (len); +} + +void +bytes_out::buf (const void *src, size_t len) +{ + if (void *ptr = buf (len)) + memcpy (ptr, src, len); +} + +const void * +bytes_in::buf (size_t len) +{ + align (sizeof (void *) * 2); + const char *ptr = read (len); + + return ptr; +} + +/* strings as an size_t length, followed by the buffer. Make sure + there's a NUL terminator on read. */ + +void +bytes_out::str (const char *string, size_t len) +{ + z (len); + if (len) + { + gcc_checking_assert (!string[len]); + buf (string, len + 1); + } +} + +const char * +bytes_in::str (size_t *len_p) +{ + size_t len = z (); + + /* We're about to trust some user data. */ + if (overrun) + len = 0; + if (len_p) + *len_p = len; + const char *str = NULL; + if (len) + { + str = reinterpret_cast<const char *> (buf (len + 1)); + if (!str || str[len]) + { + set_overrun (); + str = NULL; + } + } + return str ? str : ""; +} + +cpp_hashnode * +bytes_in::cpp_node () +{ + size_t len; + const char *s = str (&len); + if (!len) + return NULL; + return ::cpp_node (get_identifier_with_length (s, len)); +} + +/* Format a string directly to the buffer, including a terminating + NUL. Intended for human consumption. */ + +void +bytes_out::printf (const char *format, ...) +{ + va_list args; + /* Exercise buffer expansion. */ + size_t len = EXPERIMENT (10, 500); + + while (char *ptr = write (len)) + { + va_start (args, format); + size_t actual = vsnprintf (ptr, len, format, args) + 1; + va_end (args); + if (actual <= len) + { + unuse (len - actual); + break; + } + unuse (len); + len = actual; + } +} + +void +bytes_out::print_time (const char *kind, const tm *time, const char *tz) +{ + printf ("%stime: %4u/%02u/%02u %02u:%02u:%02u %s", + kind, time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec, tz); +} + +/* Encapsulated Lazy Records Of Named Declarations. + Header: Stunningly Elf32_Ehdr-like + Sections: Sectional data + [1-N) : User data sections + N .strtab : strings, stunningly ELF STRTAB-like + Index: Section table, stunningly ELF32_Shdr-like. */ + +class elf { +protected: + /* Constants used within the format. */ + enum private_constants { + /* File kind. */ + ET_NONE = 0, + EM_NONE = 0, + OSABI_NONE = 0, + + /* File format. */ + EV_CURRENT = 1, + CLASS32 = 1, + DATA2LSB = 1, + DATA2MSB = 2, + + /* Section numbering. */ + SHN_UNDEF = 0, + SHN_LORESERVE = 0xff00, + SHN_XINDEX = 0xffff, + + /* Section types. */ + SHT_NONE = 0, /* No contents. */ + SHT_PROGBITS = 1, /* Random bytes. */ + SHT_STRTAB = 3, /* A string table. */ + + /* Section flags. */ + SHF_NONE = 0x00, /* Nothing. */ + SHF_STRINGS = 0x20, /* NUL-Terminated strings. */ + + /* I really hope we do not get CMI files larger than 4GB. */ + MY_CLASS = CLASS32, + /* It is host endianness that is relevant. */ + MY_ENDIAN = DATA2LSB +#ifdef WORDS_BIGENDIAN + ^ DATA2LSB ^ DATA2MSB +#endif + }; + +public: + /* Constants visible to users. */ + enum public_constants { + /* Special error codes. Breaking layering a bit. */ + E_BAD_DATA = -1, /* Random unexpected data errors. */ + E_BAD_LAZY = -2, /* Badly ordered laziness. */ + E_BAD_IMPORT = -3 /* A nested import failed. */ + }; + +protected: + /* File identification. On-disk representation. */ + struct ident { + uint8_t magic[4]; /* 0x7f, 'E', 'L', 'F' */ + uint8_t klass; /* 4:CLASS32 */ + uint8_t data; /* 5:DATA2[LM]SB */ + uint8_t version; /* 6:EV_CURRENT */ + uint8_t osabi; /* 7:OSABI_NONE */ + uint8_t abiver; /* 8: 0 */ + uint8_t pad[7]; /* 9-15 */ + }; + /* File header. On-disk representation. */ + struct header { + struct ident ident; + uint16_t type; /* ET_NONE */ + uint16_t machine; /* EM_NONE */ + uint32_t version; /* EV_CURRENT */ + uint32_t entry; /* 0 */ + uint32_t phoff; /* 0 */ + uint32_t shoff; /* Section Header Offset in file */ + uint32_t flags; + uint16_t ehsize; /* ELROND Header SIZE -- sizeof (header) */ + uint16_t phentsize; /* 0 */ + uint16_t phnum; /* 0 */ + uint16_t shentsize; /* Section Header SIZE -- sizeof (section) */ + uint16_t shnum; /* Section Header NUM */ + uint16_t shstrndx; /* Section Header STRing iNDeX */ + }; + /* File section. On-disk representation. */ + struct section { + uint32_t name; /* String table offset. */ + uint32_t type; /* SHT_* */ + uint32_t flags; /* SHF_* */ + uint32_t addr; /* 0 */ + uint32_t offset; /* OFFSET in file */ + uint32_t size; /* SIZE of section */ + uint32_t link; /* 0 */ + uint32_t info; /* 0 */ + uint32_t addralign; /* 0 */ + uint32_t entsize; /* ENTry SIZE, usually 0 */ + }; + +protected: + data hdr; /* The header. */ + data sectab; /* The section table. */ + data strtab; /* String table. */ + int fd; /* File descriptor we're reading or writing. */ + int err; /* Sticky error code. */ + +public: + /* Construct from STREAM. E is errno if STREAM NULL. */ + elf (int fd, int e) + :hdr (), sectab (), strtab (), fd (fd), err (fd >= 0 ? 0 : e) + {} + ~elf () + { + gcc_checking_assert (fd < 0 && !hdr.buffer + && !sectab.buffer && !strtab.buffer); + } + +public: + /* Return the error, if we have an error. */ + int get_error () const + { + return err; + } + /* Set the error, unless it's already been set. */ + void set_error (int e = E_BAD_DATA) + { + if (!err) + err = e; + } + /* Get an error string. */ + const char *get_error (const char *) const; + +public: + /* Begin reading/writing file. Return false on error. */ + bool begin () const + { + return !get_error (); + } + /* Finish reading/writing file. Return false on error. */ + bool end (); +}; + +/* Return error string. */ + +const char * +elf::get_error (const char *name) const +{ + if (!name) + return "Unknown CMI mapping"; + + switch (err) + { + case 0: + gcc_unreachable (); + case E_BAD_DATA: + return "Bad file data"; + case E_BAD_IMPORT: + return "Bad import dependency"; + case E_BAD_LAZY: + return "Bad lazy ordering"; + default: + return xstrerror (err); + } +} + +/* Finish file, return true if there's an error. */ + +bool +elf::end () +{ + /* Close the stream and free the section table. */ + if (fd >= 0 && close (fd)) + set_error (errno); + fd = -1; + + return !get_error (); +} + +/* ELROND reader. */ + +class elf_in : public elf { + typedef elf parent; + +private: + /* For freezing & defrosting. */ +#if !defined (HOST_LACKS_INODE_NUMBERS) + dev_t device; + ino_t inode; +#endif + +public: + elf_in (int fd, int e) + :parent (fd, e) + { + } + ~elf_in () + { + } + +public: + bool is_frozen () const + { + return fd < 0 && hdr.pos; + } + bool is_freezable () const + { + return fd >= 0 && hdr.pos; + } + void freeze (); + bool defrost (const char *); + + /* If BYTES is in the mmapped area, allocate a new buffer for it. */ + void preserve (bytes_in &bytes ATTRIBUTE_UNUSED) + { +#if MAPPED_READING + if (hdr.buffer && bytes.buffer >= hdr.buffer + && bytes.buffer < hdr.buffer + hdr.pos) + { + char *buf = bytes.buffer; + bytes.buffer = data::simple_memory.grow (NULL, bytes.size); + memcpy (bytes.buffer, buf, bytes.size); + } +#endif + } + /* If BYTES is not in SELF's mmapped area, free it. SELF might be + NULL. */ + static void release (elf_in *self ATTRIBUTE_UNUSED, bytes_in &bytes) + { +#if MAPPED_READING + if (!(self && self->hdr.buffer && bytes.buffer >= self->hdr.buffer + && bytes.buffer < self->hdr.buffer + self->hdr.pos)) +#endif + data::simple_memory.shrink (bytes.buffer); + bytes.buffer = NULL; + bytes.size = 0; + } + +public: + static void grow (data &data, unsigned needed) + { + gcc_checking_assert (!data.buffer); +#if !MAPPED_READING + data.buffer = XNEWVEC (char, needed); +#endif + data.size = needed; + } + static void shrink (data &data) + { +#if !MAPPED_READING + XDELETEVEC (data.buffer); +#endif + data.buffer = NULL; + data.size = 0; + } + +public: + const section *get_section (unsigned s) const + { + if (s * sizeof (section) < sectab.size) + return reinterpret_cast<const section *> + (§ab.buffer[s * sizeof (section)]); + else + return NULL; + } + unsigned get_section_limit () const + { + return sectab.size / sizeof (section); + } + +protected: + const char *read (data *, unsigned, unsigned); + +public: + /* Read section by number. */ + bool read (data *d, const section *s) + { + return s && read (d, s->offset, s->size); + } + + /* Find section by name. */ + unsigned find (const char *name); + /* Find section by index. */ + const section *find (unsigned snum, unsigned type = SHT_PROGBITS); + +public: + /* Release the string table, when we're done with it. */ + void release () + { + shrink (strtab); + } + +public: + bool begin (location_t); + bool end () + { + release (); +#if MAPPED_READING + if (hdr.buffer) + munmap (hdr.buffer, hdr.pos); + hdr.buffer = NULL; +#endif + shrink (sectab); + + return parent::end (); + } + +public: + /* Return string name at OFFSET. Checks OFFSET range. Always + returns non-NULL. We know offset 0 is an empty string. */ + const char *name (unsigned offset) + { + return &strtab.buffer[offset < strtab.size ? offset : 0]; + } +}; + +/* ELROND writer. */ + +class elf_out : public elf, public data::allocator { + typedef elf parent; + /* Desired section alignment on disk. */ + static const int SECTION_ALIGN = 16; + +private: + ptr_int_hash_map identtab; /* Map of IDENTIFIERS to strtab offsets. */ + unsigned pos; /* Write position in file. */ +#if MAPPED_WRITING + unsigned offset; /* Offset of the mapping. */ + unsigned extent; /* Length of mapping. */ + unsigned page_size; /* System page size. */ +#endif + +public: + elf_out (int fd, int e) + :parent (fd, e), identtab (500), pos (0) + { +#if MAPPED_WRITING + offset = extent = 0; + page_size = sysconf (_SC_PAGE_SIZE); + if (page_size < SECTION_ALIGN) + /* Something really strange. */ + set_error (EINVAL); +#endif + } + ~elf_out () + { + data::simple_memory.shrink (hdr); + data::simple_memory.shrink (sectab); + data::simple_memory.shrink (strtab); + } + +#if MAPPED_WRITING +private: + void create_mapping (unsigned ext, bool extending = true); + void remove_mapping (); +#endif + +protected: + using allocator::grow; + virtual char *grow (char *, unsigned needed); +#if MAPPED_WRITING + using allocator::shrink; + virtual void shrink (char *); +#endif + +public: + unsigned get_section_limit () const + { + return sectab.pos / sizeof (section); + } + +protected: + unsigned add (unsigned type, unsigned name = 0, + unsigned off = 0, unsigned size = 0, unsigned flags = SHF_NONE); + unsigned write (const data &); +#if MAPPED_WRITING + unsigned write (const bytes_out &); +#endif + +public: + /* IDENTIFIER to strtab offset. */ + unsigned name (tree ident); + /* String literal to strtab offset. */ + unsigned name (const char *n); + /* Qualified name of DECL to strtab offset. */ + unsigned qualified_name (tree decl, bool is_defn); + +private: + unsigned strtab_write (const char *s, unsigned l); + void strtab_write (tree decl, int); + +public: + /* Add a section with contents or strings. */ + unsigned add (const bytes_out &, bool string_p, unsigned name); + +public: + /* Begin and end writing. */ + bool begin (); + bool end (); +}; + +/* Begin reading section NAME (of type PROGBITS) from SOURCE. + Data always checked for CRC. */ + +bool +bytes_in::begin (location_t loc, elf_in *source, const char *name) +{ + unsigned snum = source->find (name); + + return begin (loc, source, snum, name); +} + +/* Begin reading section numbered SNUM with NAME (may be NULL). */ + +bool +bytes_in::begin (location_t loc, elf_in *source, unsigned snum, const char *name) +{ + if (!source->read (this, source->find (snum)) + || !size || !check_crc ()) + { + source->set_error (elf::E_BAD_DATA); + source->shrink (*this); + if (name) + error_at (loc, "section %qs is missing or corrupted", name); + else + error_at (loc, "section #%u is missing or corrupted", snum); + return false; + } + pos = 4; + return true; +} + +/* Finish reading a section. */ + +bool +bytes_in::end (elf_in *src) +{ + if (more_p ()) + set_overrun (); + if (overrun) + src->set_error (); + + src->shrink (*this); + + return !overrun; +} + +/* Begin writing buffer. */ + +void +bytes_out::begin (bool need_crc) +{ + if (need_crc) + pos = 4; + memory->grow (*this, 0, false); +} + +/* Finish writing buffer. Stream out to SINK as named section NAME. + Return section number or 0 on failure. If CRC_PTR is true, crc + the data. Otherwise it is a string section. */ + +unsigned +bytes_out::end (elf_out *sink, unsigned name, unsigned *crc_ptr) +{ + lengths[3] += pos; + spans[3]++; + + set_crc (crc_ptr); + unsigned sec_num = sink->add (*this, !crc_ptr, name); + memory->shrink (*this); + + return sec_num; +} + +/* Close and open the file, without destroying it. */ + +void +elf_in::freeze () +{ + gcc_checking_assert (!is_frozen ()); +#if MAPPED_READING + if (munmap (hdr.buffer, hdr.pos) < 0) + set_error (errno); +#endif + if (close (fd) < 0) + set_error (errno); + fd = -1; +} + +bool +elf_in::defrost (const char *name) +{ + gcc_checking_assert (is_frozen ()); + struct stat stat; + + fd = open (name, O_RDONLY | O_CLOEXEC | O_BINARY); + if (fd < 0 || fstat (fd, &stat) < 0) + set_error (errno); + else + { + bool ok = hdr.pos == unsigned (stat.st_size); +#ifndef HOST_LACKS_INODE_NUMBERS + if (device != stat.st_dev + || inode != stat.st_ino) + ok = false; +#endif + if (!ok) + set_error (EMFILE); +#if MAPPED_READING + if (ok) + { + char *mapping = reinterpret_cast<char *> + (mmap (NULL, hdr.pos, PROT_READ, MAP_SHARED, fd, 0)); + if (mapping == MAP_FAILED) + fail: + set_error (errno); + else + { + if (madvise (mapping, hdr.pos, MADV_RANDOM)) + goto fail; + + /* These buffers are never NULL in this case. */ + strtab.buffer = mapping + strtab.pos; + sectab.buffer = mapping + sectab.pos; + hdr.buffer = mapping; + } + } +#endif + } + + return !get_error (); +} + +/* Read at current position into BUFFER. Return true on success. */ + +const char * +elf_in::read (data *data, unsigned pos, unsigned length) +{ +#if MAPPED_READING + if (pos + length > hdr.pos) + { + set_error (EINVAL); + return NULL; + } +#else + if (pos != ~0u && lseek (fd, pos, SEEK_SET) < 0) + { + set_error (errno); + return NULL; + } +#endif + grow (*data, length); +#if MAPPED_READING + data->buffer = hdr.buffer + pos; +#else + if (::read (fd, data->buffer, data->size) != ssize_t (length)) + { + set_error (errno); + shrink (*data); + return NULL; + } +#endif + + return data->buffer; +} + +/* Read section SNUM of TYPE. Return section pointer or NULL on error. */ + +const elf::section * +elf_in::find (unsigned snum, unsigned type) +{ + const section *sec = get_section (snum); + if (!snum || !sec || sec->type != type) + return NULL; + return sec; +} + +/* Find a section NAME and TYPE. Return section number, or zero on + failure. */ + +unsigned +elf_in::find (const char *sname) +{ + for (unsigned pos = sectab.size; pos -= sizeof (section); ) + { + const section *sec + = reinterpret_cast<const section *> (§ab.buffer[pos]); + + if (0 == strcmp (sname, name (sec->name))) + return pos / sizeof (section); + } + + return 0; +} + +/* Begin reading file. Verify header. Pull in section and string + tables. Return true on success. */ + +bool +elf_in::begin (location_t loc) +{ + if (!parent::begin ()) + return false; + + struct stat stat; + unsigned size = 0; + if (!fstat (fd, &stat)) + { +#if !defined (HOST_LACKS_INODE_NUMBERS) + device = stat.st_dev; + inode = stat.st_ino; +#endif + /* Never generate files > 4GB, check we've not been given one. */ + if (stat.st_size == unsigned (stat.st_size)) + size = unsigned (stat.st_size); + } + +#if MAPPED_READING + /* MAP_SHARED so that the file is backing store. If someone else + concurrently writes it, they're wrong. */ + void *mapping = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) + { + fail: + set_error (errno); + return false; + } + /* We'll be hopping over this randomly. Some systems declare the + first parm as char *, and other declare it as void *. */ + if (madvise (reinterpret_cast <char *> (mapping), size, MADV_RANDOM)) + goto fail; + + hdr.buffer = (char *)mapping; +#else + read (&hdr, 0, sizeof (header)); +#endif + hdr.pos = size; /* Record size of the file. */ + + const header *h = reinterpret_cast<const header *> (hdr.buffer); + if (!h) + return false; + + if (h->ident.magic[0] != 0x7f + || h->ident.magic[1] != 'E' + || h->ident.magic[2] != 'L' + || h->ident.magic[3] != 'F') + { + error_at (loc, "not Encapsulated Lazy Records of Named Declarations"); + failed: + shrink (hdr); + return false; + } + + /* We expect a particular format -- the ELF is not intended to be + distributable. */ + if (h->ident.klass != MY_CLASS + || h->ident.data != MY_ENDIAN + || h->ident.version != EV_CURRENT + || h->type != ET_NONE + || h->machine != EM_NONE + || h->ident.osabi != OSABI_NONE) + { + error_at (loc, "unexpected encapsulation format or type"); + goto failed; + } + + int e = -1; + if (!h->shoff || h->shentsize != sizeof (section)) + { + malformed: + set_error (e); + error_at (loc, "encapsulation is malformed"); + goto failed; + } + + unsigned strndx = h->shstrndx; + unsigned shnum = h->shnum; + if (shnum == SHN_XINDEX) + { + if (!read (§ab, h->shoff, sizeof (section))) + { + section_table_fail: + e = errno; + goto malformed; + } + shnum = get_section (0)->size; + /* Freeing does mean we'll re-read it in the case we're not + mapping, but this is going to be rare. */ + shrink (sectab); + } + + if (!shnum) + goto malformed; + + if (!read (§ab, h->shoff, shnum * sizeof (section))) + goto section_table_fail; + + if (strndx == SHN_XINDEX) + strndx = get_section (0)->link; + + if (!read (&strtab, find (strndx, SHT_STRTAB))) + goto malformed; + + /* The string table should be at least one byte, with NUL chars + at either end. */ + if (!(strtab.size && !strtab.buffer[0] + && !strtab.buffer[strtab.size - 1])) + goto malformed; + +#if MAPPED_READING + /* Record the offsets of the section and string tables. */ + sectab.pos = h->shoff; + strtab.pos = shnum * sizeof (section); +#else + shrink (hdr); +#endif + + return true; +} + +/* Create a new mapping. */ + +#if MAPPED_WRITING +void +elf_out::create_mapping (unsigned ext, bool extending) +{ +#ifndef HAVE_POSIX_FALLOCATE +#define posix_fallocate(fd,off,len) ftruncate (fd, off + len) +#endif + void *mapping = MAP_FAILED; + if (extending && ext < 1024 * 1024) + { + if (!posix_fallocate (fd, offset, ext * 2)) + mapping = mmap (NULL, ext * 2, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, offset); + if (mapping != MAP_FAILED) + ext *= 2; + } + if (mapping == MAP_FAILED) + { + if (!extending || !posix_fallocate (fd, offset, ext)) + mapping = mmap (NULL, ext, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, offset); + if (mapping == MAP_FAILED) + { + set_error (errno); + mapping = NULL; + ext = 0; + } + } +#undef posix_fallocate + hdr.buffer = (char *)mapping; + extent = ext; +} +#endif + +/* Flush out the current mapping. */ + +#if MAPPED_WRITING +void +elf_out::remove_mapping () +{ + if (hdr.buffer) + { + /* MS_ASYNC dtrt with the removed mapping, including a + subsequent overlapping remap. */ + if (msync (hdr.buffer, extent, MS_ASYNC) + || munmap (hdr.buffer, extent)) + /* We're somewhat screwed at this point. */ + set_error (errno); + } + + hdr.buffer = NULL; +} +#endif + +/* Grow a mapping of PTR to be NEEDED bytes long. This gets + interesting if the new size grows the EXTENT. */ + +char * +elf_out::grow (char *data, unsigned needed) +{ + if (!data) + { + /* First allocation, check we're aligned. */ + gcc_checking_assert (!(pos & (SECTION_ALIGN - 1))); +#if MAPPED_WRITING + data = hdr.buffer + (pos - offset); +#endif + } + +#if MAPPED_WRITING + unsigned off = data - hdr.buffer; + if (off + needed > extent) + { + /* We need to grow the mapping. */ + unsigned lwm = off & ~(page_size - 1); + unsigned hwm = (off + needed + page_size - 1) & ~(page_size - 1); + + gcc_checking_assert (hwm > extent); + + remove_mapping (); + + offset += lwm; + create_mapping (extent < hwm - lwm ? hwm - lwm : extent); + + data = hdr.buffer + (off - lwm); + } +#else + data = allocator::grow (data, needed); +#endif + + return data; +} + +#if MAPPED_WRITING +/* Shrinking is a NOP. */ +void +elf_out::shrink (char *) +{ +} +#endif + +/* Write S of length L to the strtab buffer. L must include the ending + NUL, if that's what you want. */ + +unsigned +elf_out::strtab_write (const char *s, unsigned l) +{ + if (strtab.pos + l > strtab.size) + data::simple_memory.grow (strtab, strtab.pos + l, false); + memcpy (strtab.buffer + strtab.pos, s, l); + unsigned res = strtab.pos; + strtab.pos += l; + return res; +} + +/* Write qualified name of decl. INNER >0 if this is a definition, <0 + if this is a qualifier of an outer name. */ + +void +elf_out::strtab_write (tree decl, int inner) +{ + tree ctx = CP_DECL_CONTEXT (decl); + if (TYPE_P (ctx)) + ctx = TYPE_NAME (ctx); + if (ctx != global_namespace) + strtab_write (ctx, -1); + + tree name = DECL_NAME (decl); + if (!name) + name = DECL_ASSEMBLER_NAME_RAW (decl); + strtab_write (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)); + + if (inner) + strtab_write (&"::{}"[inner+1], 2); +} + +/* Map IDENTIFIER IDENT to strtab offset. Inserts into strtab if not + already there. */ + +unsigned +elf_out::name (tree ident) +{ + unsigned res = 0; + if (ident) + { + bool existed; + int *slot = &identtab.get_or_insert (ident, &existed); + if (!existed) + *slot = strtab_write (IDENTIFIER_POINTER (ident), + IDENTIFIER_LENGTH (ident) + 1); + res = *slot; + } + return res; +} + +/* Map LITERAL to strtab offset. Does not detect duplicates and + expects LITERAL to remain live until strtab is written out. */ + +unsigned +elf_out::name (const char *literal) +{ + return strtab_write (literal, strlen (literal) + 1); +} + +/* Map a DECL's qualified name to strtab offset. Does not detect + duplicates. */ + +unsigned +elf_out::qualified_name (tree decl, bool is_defn) +{ + gcc_checking_assert (DECL_P (decl) && decl != global_namespace); + unsigned result = strtab.pos; + + strtab_write (decl, is_defn); + strtab_write ("", 1); + + return result; +} + +/* Add section to file. Return section number. TYPE & NAME identify + the section. OFF and SIZE identify the file location of its + data. FLAGS contains additional info. */ + +unsigned +elf_out::add (unsigned type, unsigned name, unsigned off, unsigned size, + unsigned flags) +{ + gcc_checking_assert (!(off & (SECTION_ALIGN - 1))); + if (sectab.pos + sizeof (section) > sectab.size) + data::simple_memory.grow (sectab, sectab.pos + sizeof (section), false); + section *sec = reinterpret_cast<section *> (sectab.buffer + sectab.pos); + memset (sec, 0, sizeof (section)); + sec->type = type; + sec->flags = flags; + sec->name = name; + sec->offset = off; + sec->size = size; + if (flags & SHF_STRINGS) + sec->entsize = 1; + + unsigned res = sectab.pos; + sectab.pos += sizeof (section); + return res / sizeof (section); +} + +/* Pad to the next alignment boundary, then write BUFFER to disk. + Return the position of the start of the write, or zero on failure. */ + +unsigned +elf_out::write (const data &buffer) +{ +#if MAPPED_WRITING + /* HDR is always mapped. */ + if (&buffer != &hdr) + { + bytes_out out (this); + grow (out, buffer.pos, true); + if (out.buffer) + memcpy (out.buffer, buffer.buffer, buffer.pos); + shrink (out); + } + else + /* We should have been aligned during the first allocation. */ + gcc_checking_assert (!(pos & (SECTION_ALIGN - 1))); +#else + if (::write (fd, buffer.buffer, buffer.pos) != ssize_t (buffer.pos)) + { + set_error (errno); + return 0; + } +#endif + unsigned res = pos; + pos += buffer.pos; + + if (unsigned padding = -pos & (SECTION_ALIGN - 1)) + { +#if !MAPPED_WRITING + /* Align the section on disk, should help the necessary copies. + fseeking to extend is non-portable. */ + static char zero[SECTION_ALIGN]; + if (::write (fd, &zero, padding) != ssize_t (padding)) + set_error (errno); +#endif + pos += padding; + } + return res; +} + +/* Write a streaming buffer. It must be using us as an allocator. */ + +#if MAPPED_WRITING +unsigned +elf_out::write (const bytes_out &buf) +{ + gcc_checking_assert (buf.memory == this); + /* A directly mapped buffer. */ + gcc_checking_assert (buf.buffer - hdr.buffer >= 0 + && buf.buffer - hdr.buffer + buf.size <= extent); + unsigned res = pos; + pos += buf.pos; + + /* Align up. We're not going to advance into the next page. */ + pos += -pos & (SECTION_ALIGN - 1); + + return res; +} +#endif + +/* Write data and add section. STRING_P is true for a string + section, false for PROGBITS. NAME identifies the section (0 is the + empty name). DATA is the contents. Return section number or 0 on + failure (0 is the undef section). */ + +unsigned +elf_out::add (const bytes_out &data, bool string_p, unsigned name) +{ + unsigned off = write (data); + + return add (string_p ? SHT_STRTAB : SHT_PROGBITS, name, + off, data.pos, string_p ? SHF_STRINGS : SHF_NONE); +} + +/* Begin writing the file. Initialize the section table and write an + empty header. Return false on failure. */ + +bool +elf_out::begin () +{ + if (!parent::begin ()) + return false; + + /* Let the allocators pick a default. */ + data::simple_memory.grow (strtab, 0, false); + data::simple_memory.grow (sectab, 0, false); + + /* The string table starts with an empty string. */ + name (""); + + /* Create the UNDEF section. */ + add (SHT_NONE); + +#if MAPPED_WRITING + /* Start a mapping. */ + create_mapping (EXPERIMENT (page_size, + (32767 + page_size) & ~(page_size - 1))); + if (!hdr.buffer) + return false; +#endif + + /* Write an empty header. */ + grow (hdr, sizeof (header), true); + header *h = reinterpret_cast<header *> (hdr.buffer); + memset (h, 0, sizeof (header)); + hdr.pos = hdr.size; + write (hdr); + return !get_error (); +} + +/* Finish writing the file. Write out the string & section tables. + Fill in the header. Return true on error. */ + +bool +elf_out::end () +{ + if (fd >= 0) + { + /* Write the string table. */ + unsigned strnam = name (".strtab"); + unsigned stroff = write (strtab); + unsigned strndx = add (SHT_STRTAB, strnam, stroff, strtab.pos, + SHF_STRINGS); + + /* Store escape values in section[0]. */ + if (strndx >= SHN_LORESERVE) + { + reinterpret_cast<section *> (sectab.buffer)->link = strndx; + strndx = SHN_XINDEX; + } + unsigned shnum = sectab.pos / sizeof (section); + if (shnum >= SHN_LORESERVE) + { + reinterpret_cast<section *> (sectab.buffer)->size = shnum; + shnum = SHN_XINDEX; + } + + unsigned shoff = write (sectab); + +#if MAPPED_WRITING + if (offset) + { + remove_mapping (); + offset = 0; + create_mapping ((sizeof (header) + page_size - 1) & ~(page_size - 1), + false); + } + unsigned length = pos; +#else + if (lseek (fd, 0, SEEK_SET) < 0) + set_error (errno); +#endif + /* Write header. */ + if (!get_error ()) + { + /* Write the correct header now. */ + header *h = reinterpret_cast<header *> (hdr.buffer); + h->ident.magic[0] = 0x7f; + h->ident.magic[1] = 'E'; /* Elrond */ + h->ident.magic[2] = 'L'; /* is an */ + h->ident.magic[3] = 'F'; /* elf. */ + h->ident.klass = MY_CLASS; + h->ident.data = MY_ENDIAN; + h->ident.version = EV_CURRENT; + h->ident.osabi = OSABI_NONE; + h->type = ET_NONE; + h->machine = EM_NONE; + h->version = EV_CURRENT; + h->shoff = shoff; + h->ehsize = sizeof (header); + h->shentsize = sizeof (section); + h->shnum = shnum; + h->shstrndx = strndx; + + pos = 0; + write (hdr); + } + +#if MAPPED_WRITING + remove_mapping (); + if (ftruncate (fd, length)) + set_error (errno); +#endif + } + + data::simple_memory.shrink (sectab); + data::simple_memory.shrink (strtab); + + return parent::end (); +} + +/********************************************************************/ + +/* A dependency set. This is used during stream out to determine the + connectivity of the graph. Every namespace-scope declaration that + needs writing has a depset. The depset is filled with the (depsets + of) declarations within this module that it references. For a + declaration that'll generally be named types. For definitions + it'll also be declarations in the body. + + From that we can convert the graph to a DAG, via determining the + Strongly Connected Clusters. Each cluster is streamed + independently, and thus we achieve lazy loading. + + Other decls that get a depset are namespaces themselves and + unnameable declarations. */ + +class depset { +private: + tree entity; /* Entity, or containing namespace. */ + uintptr_t discriminator; /* Flags or identifier. */ + +public: + /* The kinds of entity the depset could describe. The ordering is + significant, see entity_kind_name. */ + enum entity_kind + { + EK_DECL, /* A decl. */ + EK_SPECIALIZATION, /* A specialization. */ + EK_PARTIAL, /* A partial specialization. */ + EK_USING, /* A using declaration (at namespace scope). */ + EK_NAMESPACE, /* A namespace. */ + EK_REDIRECT, /* Redirect to a template_decl. */ + EK_EXPLICIT_HWM, + EK_BINDING = EK_EXPLICIT_HWM, /* Implicitly encoded. */ + EK_FOR_BINDING, /* A decl being inserted for a binding. */ + EK_INNER_DECL, /* A decl defined outside of it's imported + context. */ + EK_DIRECT_HWM = EK_PARTIAL + 1, + + EK_BITS = 3 /* Only need to encode below EK_EXPLICIT_HWM. */ + }; + +private: + /* Placement of bit fields in discriminator. */ + enum disc_bits + { + DB_ZERO_BIT, /* Set to disambiguate identifier from flags */ + DB_SPECIAL_BIT, /* First dep slot is special. */ + DB_KIND_BIT, /* Kind of the entity. */ + DB_KIND_BITS = EK_BITS, + DB_DEFN_BIT = DB_KIND_BIT + DB_KIND_BITS, + DB_IS_MEMBER_BIT, /* Is an out-of-class member. */ + DB_IS_INTERNAL_BIT, /* It is an (erroneous) + internal-linkage entity. */ + DB_REFS_INTERNAL_BIT, /* Refers to an internal-linkage + entity. */ + DB_IMPORTED_BIT, /* An imported entity. */ + DB_UNREACHED_BIT, /* A yet-to-be reached entity. */ + DB_HIDDEN_BIT, /* A hidden binding. */ + /* The following bits are not independent, but enumerating them is + awkward. */ + DB_ALIAS_TMPL_INST_BIT, /* An alias template instantiation. */ + DB_ALIAS_SPEC_BIT, /* Specialization of an alias template + (in both spec tables). */ + DB_TYPE_SPEC_BIT, /* Specialization in the type table. + */ + DB_FRIEND_SPEC_BIT, /* An instantiated template friend. */ + }; + +public: + /* The first slot is special for EK_SPECIALIZATIONS it is a + spec_entry pointer. It is not relevant for the SCC + determination. */ + vec<depset *> deps; /* Depsets we reference. */ + +public: + unsigned cluster; /* Strongly connected cluster, later entity number */ + unsigned section; /* Section written to. */ + /* During SCC construction, section is lowlink, until the depset is + removed from the stack. See Tarjan algorithm for details. */ + +private: + /* Construction via factories. Destruction via hash traits. */ + depset (tree entity); + ~depset (); + +public: + static depset *make_binding (tree, tree); + static depset *make_entity (tree, entity_kind, bool = false); + /* Late setting a binding name -- /then/ insert into hash! */ + inline void set_binding_name (tree name) + { + gcc_checking_assert (!get_name ()); + discriminator = reinterpret_cast<uintptr_t> (name); + } + +private: + template<unsigned I> void set_flag_bit () + { + gcc_checking_assert (I < 2 || !is_binding ()); + discriminator |= 1u << I; + } + template<unsigned I> void clear_flag_bit () + { + gcc_checking_assert (I < 2 || !is_binding ()); + discriminator &= ~(1u << I); + } + template<unsigned I> bool get_flag_bit () const + { + gcc_checking_assert (I < 2 || !is_binding ()); + return bool ((discriminator >> I) & 1); + } + +public: + bool is_binding () const + { + return !get_flag_bit<DB_ZERO_BIT> (); + } + entity_kind get_entity_kind () const + { + if (is_binding ()) + return EK_BINDING; + return entity_kind ((discriminator >> DB_KIND_BIT) & ((1u << EK_BITS) - 1)); + } + const char *entity_kind_name () const; + +public: + bool has_defn () const + { + return get_flag_bit<DB_DEFN_BIT> (); + } + +public: + bool is_member () const + { + return get_flag_bit<DB_IS_MEMBER_BIT> (); + } +public: + bool is_internal () const + { + return get_flag_bit<DB_IS_INTERNAL_BIT> (); + } + bool refs_internal () const + { + return get_flag_bit<DB_REFS_INTERNAL_BIT> (); + } + bool is_import () const + { + return get_flag_bit<DB_IMPORTED_BIT> (); + } + bool is_unreached () const + { + return get_flag_bit<DB_UNREACHED_BIT> (); + } + bool is_alias_tmpl_inst () const + { + return get_flag_bit<DB_ALIAS_TMPL_INST_BIT> (); + } + bool is_alias () const + { + return get_flag_bit<DB_ALIAS_SPEC_BIT> (); + } + bool is_hidden () const + { + return get_flag_bit<DB_HIDDEN_BIT> (); + } + bool is_type_spec () const + { + return get_flag_bit<DB_TYPE_SPEC_BIT> (); + } + bool is_friend_spec () const + { + return get_flag_bit<DB_FRIEND_SPEC_BIT> (); + } + +public: + /* We set these bit outside of depset. */ + void set_hidden_binding () + { + set_flag_bit<DB_HIDDEN_BIT> (); + } + void clear_hidden_binding () + { + clear_flag_bit<DB_HIDDEN_BIT> (); + } + +public: + bool is_special () const + { + return get_flag_bit<DB_SPECIAL_BIT> (); + } + void set_special () + { + set_flag_bit<DB_SPECIAL_BIT> (); + } + +public: + tree get_entity () const + { + return entity; + } + tree get_name () const + { + gcc_checking_assert (is_binding ()); + return reinterpret_cast <tree> (discriminator); + } + +public: + /* Traits for a hash table of pointers to bindings. */ + struct traits { + /* Each entry is a pointer to a depset. */ + typedef depset *value_type; + /* We lookup by container:maybe-identifier pair. */ + typedef std::pair<tree,tree> compare_type; + + static const bool empty_zero_p = true; + + /* hash and equality for compare_type. */ + inline static hashval_t hash (const compare_type &p) + { + hashval_t h = pointer_hash<tree_node>::hash (p.first); + if (p.second) + { + hashval_t nh = IDENTIFIER_HASH_VALUE (p.second); + h = iterative_hash_hashval_t (h, nh); + } + return h; + } + inline static bool equal (const value_type b, const compare_type &p) + { + if (b->entity != p.first) + return false; + + if (p.second) + return b->discriminator == reinterpret_cast<uintptr_t> (p.second); + else + return !b->is_binding (); + } + + /* (re)hasher for a binding itself. */ + inline static hashval_t hash (const value_type b) + { + hashval_t h = pointer_hash<tree_node>::hash (b->entity); + if (b->is_binding ()) + { + hashval_t nh = IDENTIFIER_HASH_VALUE (b->get_name ()); + h = iterative_hash_hashval_t (h, nh); + } + return h; + } + + /* Empty via NULL. */ + static inline void mark_empty (value_type &p) {p = NULL;} + static inline bool is_empty (value_type p) {return !p;} + + /* Nothing is deletable. Everything is insertable. */ + static bool is_deleted (value_type) { return false; } + static void mark_deleted (value_type) { gcc_unreachable (); } + + /* We own the entities in the hash table. */ + static void remove (value_type p) + { + delete (p); + } + }; + +public: + class hash : public hash_table<traits> { + typedef traits::compare_type key_t; + typedef hash_table<traits> parent; + + public: + vec<depset *> worklist; /* Worklist of decls to walk. */ + hash *chain; /* Original table. */ + depset *current; /* Current depset being depended. */ + unsigned section; /* When writing out, the section. */ + bool sneakoscope; /* Detecting dark magic (of a voldemort). */ + bool reached_unreached; /* We reached an unreached entity. */ + + public: + hash (size_t size, hash *c = NULL) + : parent (size), chain (c), current (NULL), section (0), + sneakoscope (false), reached_unreached (false) + { + worklist.create (size); + } + ~hash () + { + worklist.release (); + } + + public: + bool is_key_order () const + { + return chain != NULL; + } + + private: + depset **entity_slot (tree entity, bool = true); + depset **binding_slot (tree ctx, tree name, bool = true); + depset *maybe_add_declaration (tree decl); + + public: + depset *find_dependency (tree entity); + depset *find_binding (tree ctx, tree name); + depset *make_dependency (tree decl, entity_kind); + void add_dependency (depset *); + + public: + void add_mergeable (depset *); + depset *add_dependency (tree decl, entity_kind); + void add_namespace_context (depset *, tree ns); + + private: + static bool add_binding_entity (tree, WMB_Flags, void *); + + public: + bool add_namespace_entities (tree ns, bitmap partitions); + void add_specializations (bool decl_p); + void add_partial_entities (vec<tree, va_gc> *); + void add_class_entities (vec<tree, va_gc> *); + + public: + void find_dependencies (module_state *); + bool finalize_dependencies (); + vec<depset *> connect (); + }; + +public: + struct tarjan { + vec<depset *> result; + vec<depset *> stack; + unsigned index; + + tarjan (unsigned size) + : index (0) + { + result.create (size); + stack.create (50); + } + ~tarjan () + { + gcc_assert (!stack.length ()); + stack.release (); + } + + public: + void connect (depset *); + }; +}; + +inline +depset::depset (tree entity) + :entity (entity), discriminator (0), cluster (0), section (0) +{ + deps.create (0); +} + +inline +depset::~depset () +{ + deps.release (); +} + +const char * +depset::entity_kind_name () const +{ + /* Same order as entity_kind. */ + static const char *const names[] = + {"decl", "specialization", "partial", "using", + "namespace", "redirect", "binding"}; + entity_kind kind = get_entity_kind (); + gcc_checking_assert (kind < sizeof (names) / sizeof(names[0])); + return names[kind]; +} + +/* Create a depset for a namespace binding NS::NAME. */ + +depset *depset::make_binding (tree ns, tree name) +{ + depset *binding = new depset (ns); + + binding->discriminator = reinterpret_cast <uintptr_t> (name); + + return binding; +} + +depset *depset::make_entity (tree entity, entity_kind ek, bool is_defn) +{ + depset *r = new depset (entity); + + r->discriminator = ((1 << DB_ZERO_BIT) + | (ek << DB_KIND_BIT) + | is_defn << DB_DEFN_BIT); + + return r; +} + +/* Values keyed to some unsigned integer. This is not GTY'd, so if + T is tree they must be reachable via some other path. */ + +template<typename T> +class uintset { +public: + unsigned key; /* Entity index of the other entity. */ + + /* Payload. */ + unsigned allocp2 : 5; /* log(2) allocated pending */ + unsigned num : 27; /* Number of pending. */ + + /* Trailing array of values. */ + T values[1]; + +public: + /* Even with ctors, we're very pod-like. */ + uintset (unsigned uid) + : key (uid), allocp2 (0), num (0) + { + } + /* Copy constructor, which is exciting because of the trailing + array. */ + uintset (const uintset *from) + { + size_t size = (offsetof (uintset, values) + + sizeof (uintset::values) * from->num); + memmove (this, from, size); + if (from->num) + allocp2++; + } + +public: + struct traits : delete_ptr_hash<uintset> { + typedef unsigned compare_type; + typedef typename delete_ptr_hash<uintset>::value_type value_type; + + /* Hash and equality for compare_type. */ + inline static hashval_t hash (const compare_type k) + { + return hashval_t (k); + } + inline static hashval_t hash (const value_type v) + { + return hash (v->key); + } + + inline static bool equal (const value_type v, const compare_type k) + { + return v->key == k; + } + }; + +public: + class hash : public hash_table<traits> + { + typedef typename traits::compare_type key_t; + typedef hash_table<traits> parent; + + public: + hash (size_t size) + : parent (size) + { + } + ~hash () + { + } + + private: + uintset **find_slot (key_t key, insert_option insert) + { + return this->find_slot_with_hash (key, traits::hash (key), insert); + } + + public: + uintset *get (key_t key, bool extract = false); + bool add (key_t key, T value); + uintset *create (key_t key, unsigned num, T init = 0); + }; +}; + +/* Add VALUE to KEY's uintset, creating it if necessary. Returns true + if we created the uintset. */ + +template<typename T> +bool +uintset<T>::hash::add (typename uintset<T>::hash::key_t key, T value) +{ + uintset **slot = this->find_slot (key, INSERT); + uintset *set = *slot; + bool is_new = !set; + + if (is_new || set->num == (1u << set->allocp2)) + { + if (set) + { + unsigned n = set->num * 2; + size_t new_size = (offsetof (uintset, values) + + sizeof (uintset (0u).values) * n); + uintset *new_set = new (::operator new (new_size)) uintset (set); + delete set; + set = new_set; + } + else + set = new (::operator new (sizeof (*set))) uintset (key); + *slot = set; + } + + set->values[set->num++] = value; + + return is_new; +} + +template<typename T> +uintset<T> * +uintset<T>::hash::create (typename uintset<T>::hash::key_t key, unsigned num, + T init) +{ + unsigned p2alloc = 0; + for (unsigned v = num; v != 1; v = (v >> 1) | (v & 1)) + p2alloc++; + + size_t new_size = (offsetof (uintset, values) + + (sizeof (uintset (0u).values) << p2alloc)); + uintset *set = new (::operator new (new_size)) uintset (key); + set->allocp2 = p2alloc; + set->num = num; + while (num--) + set->values[num] = init; + + uintset **slot = this->find_slot (key, INSERT); + gcc_checking_assert (!*slot); + *slot = set; + + return set; +} + +/* Locate KEY's uintset, potentially removing it from the hash table */ + +template<typename T> +uintset<T> * +uintset<T>::hash::get (typename uintset<T>::hash::key_t key, bool extract) +{ + uintset *res = NULL; + + if (uintset **slot = this->find_slot (key, NO_INSERT)) + { + res = *slot; + if (extract) + /* We need to remove the pendset without deleting it. */ + traits::mark_deleted (*slot); + } + + return res; +} + +/* Entities keyed to some other entity. When we load the other + entity, we mark it in some way to indicate there are further + entities to load when you start looking inside it. For instance + template specializations are keyed to their most general template. + When we instantiate that, we need to know all the partial + specializations (to pick the right template), and all the known + specializations (to avoid reinstantiating it, and/or whether it's + extern). The values split into two ranges. If !MSB set, indices + into the entity array. If MSB set, an indirection to another + pendset. */ + +typedef uintset<unsigned> pendset; +static pendset::hash *pending_table; + +/* Some entities are attached to another entitity for ODR purposes. + For example, at namespace scope, 'inline auto var = []{};', that + lambda is attached to 'var', and follows its ODRness. */ +typedef uintset<tree> attachset; +static attachset::hash *attached_table; + +/********************************************************************/ +/* Tree streaming. The tree streaming is very specific to the tree + structures themselves. A tag indicates the kind of tree being + streamed. -ve tags indicate backreferences to already-streamed + trees. Backreferences are auto-numbered. */ + +/* Tree tags. */ +enum tree_tag { + tt_null, /* NULL_TREE. */ + tt_fixed, /* Fixed vector index. */ + + tt_node, /* By-value node. */ + tt_decl, /* By-value mergeable decl. */ + tt_tpl_parm, /* Template parm. */ + + /* The ordering of the following 4 is relied upon in + trees_out::tree_node. */ + tt_id, /* Identifier node. */ + tt_conv_id, /* Conversion operator name. */ + tt_anon_id, /* Anonymous name. */ + tt_lambda_id, /* Lambda name. */ + + tt_typedef_type, /* A (possibly implicit) typedefed type. */ + tt_derived_type, /* A type derived from another type. */ + tt_variant_type, /* A variant of another type. */ + + tt_tinfo_var, /* Typeinfo object. */ + tt_tinfo_typedef, /* Typeinfo typedef. */ + tt_ptrmem_type, /* Pointer to member type. */ + + tt_parm, /* Function parameter or result. */ + tt_enum_value, /* An enum value. */ + tt_enum_decl, /* An enum decl. */ + tt_data_member, /* Data member/using-decl. */ + + tt_binfo, /* A BINFO. */ + tt_vtable, /* A vtable. */ + tt_thunk, /* A thunk. */ + tt_clone_ref, + + tt_entity, /* A extra-cluster entity. */ + + tt_template, /* The TEMPLATE_RESULT of a template. */ +}; + +enum walk_kind { + WK_none, /* No walk to do (a back- or fixed-ref happened). */ + WK_normal, /* Normal walk (by-name if possible). */ + + WK_value, /* By-value walk. */ +}; + +enum merge_kind +{ + MK_unique, /* Known unique. */ + MK_named, /* Found by CTX, NAME + maybe_arg types etc. */ + MK_field, /* Found by CTX and index on TYPE_FIELDS */ + MK_vtable, /* Found by CTX and index on TYPE_VTABLES */ + MK_as_base, /* Found by CTX. */ + + MK_partial, + + MK_enum, /* Found by CTX, & 1stMemberNAME. */ + MK_attached, /* Found by attachee & index. */ + + MK_friend_spec, /* Like named, but has a tmpl & args too. */ + MK_local_friend, /* Found by CTX, index. */ + + MK_indirect_lwm = MK_enum, + + /* Template specialization kinds below. These are all found via + primary template and specialization args. */ + MK_template_mask = 0x10, /* A template specialization. */ + + MK_tmpl_decl_mask = 0x4, /* In decl table. */ + MK_tmpl_alias_mask = 0x2, /* Also in type table */ + + MK_tmpl_tmpl_mask = 0x1, /* We want TEMPLATE_DECL. */ + + MK_type_spec = MK_template_mask, + MK_type_tmpl_spec = MK_type_spec | MK_tmpl_tmpl_mask, + + MK_decl_spec = MK_template_mask | MK_tmpl_decl_mask, + MK_decl_tmpl_spec = MK_decl_spec | MK_tmpl_tmpl_mask, + + MK_alias_spec = MK_decl_spec | MK_tmpl_alias_mask, + + MK_hwm = 0x20 +}; +/* This is more than a debugging array. NULLs are used to determine + an invalid merge_kind number. */ +static char const *const merge_kind_name[MK_hwm] = + { + "unique", "named", "field", "vtable", /* 0...3 */ + "asbase", "partial", "enum", "attached", /* 4...7 */ + + "friend spec", "local friend", NULL, NULL, /* 8...11 */ + NULL, NULL, NULL, NULL, + + "type spec", "type tmpl spec", /* 16,17 type (template). */ + NULL, NULL, + + "decl spec", "decl tmpl spec", /* 20,21 decl (template). */ + "alias spec", NULL, /* 22,23 alias. */ + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }; + +/* Mergeable entity location data. */ +struct merge_key { + cp_ref_qualifier ref_q : 2; + unsigned index; + + tree ret; /* Return type, if appropriate. */ + tree args; /* Arg types, if appropriate. */ + + tree constraints; /* Constraints. */ + + merge_key () + :ref_q (REF_QUAL_NONE), index (0), + ret (NULL_TREE), args (NULL_TREE), + constraints (NULL_TREE) + { + } +}; + +struct duplicate_hash : nodel_ptr_hash<tree_node> +{ + inline static hashval_t hash (value_type decl) + { + if (TREE_CODE (decl) == TREE_BINFO) + decl = TYPE_NAME (BINFO_TYPE (decl)); + return hashval_t (DECL_UID (decl)); + } +}; + +/* Hashmap of merged duplicates. Usually decls, but can contain + BINFOs. */ +typedef hash_map<tree,uintptr_t, + simple_hashmap_traits<duplicate_hash,uintptr_t> > +duplicate_hash_map; + +/* Tree stream reader. Note that reading a stream doesn't mark the + read trees with TREE_VISITED. Thus it's quite safe to have + multiple concurrent readers. Which is good, because lazy + loading. */ +class trees_in : public bytes_in { + typedef bytes_in parent; + +private: + module_state *state; /* Module being imported. */ + vec<tree> back_refs; /* Back references. */ + duplicate_hash_map *duplicates; /* Map from existings to duplicate. */ + vec<tree> post_decls; /* Decls to post process. */ + unsigned unused; /* Inhibit any interior TREE_USED + marking. */ + +public: + trees_in (module_state *); + ~trees_in (); + +public: + int insert (tree); + tree back_ref (int); + +private: + tree start (unsigned = 0); + +public: + /* Needed for binfo writing */ + bool core_bools (tree); + +private: + /* Stream tree_core, lang_decl_specific and lang_type_specific + bits. */ + bool core_vals (tree); + bool lang_type_bools (tree); + bool lang_type_vals (tree); + bool lang_decl_bools (tree); + bool lang_decl_vals (tree); + bool lang_vals (tree); + bool tree_node_bools (tree); + bool tree_node_vals (tree); + tree tree_value (); + tree decl_value (); + tree tpl_parm_value (); + +private: + tree chained_decls (); /* Follow DECL_CHAIN. */ + vec<tree, va_heap> *vec_chained_decls (); + vec<tree, va_gc> *tree_vec (); /* vec of tree. */ + vec<tree_pair_s, va_gc> *tree_pair_vec (); /* vec of tree_pair. */ + tree tree_list (bool has_purpose); + +public: + /* Read a tree node. */ + tree tree_node (bool is_use = false); + +private: + bool install_entity (tree decl); + tree tpl_parms (unsigned &tpl_levels); + bool tpl_parms_fini (tree decl, unsigned tpl_levels); + bool tpl_header (tree decl, unsigned *tpl_levels); + int fn_parms_init (tree); + void fn_parms_fini (int tag, tree fn, tree existing, bool has_defn); + unsigned add_indirect_tpl_parms (tree); +public: + bool add_indirects (tree); + +public: + /* Serialize various definitions. */ + bool read_definition (tree decl); + +private: + bool is_matching_decl (tree existing, tree decl, bool is_typedef); + static bool install_implicit_member (tree decl); + bool read_function_def (tree decl, tree maybe_template); + bool read_var_def (tree decl, tree maybe_template); + bool read_class_def (tree decl, tree maybe_template); + bool read_enum_def (tree decl, tree maybe_template); + +public: + tree decl_container (); + tree key_mergeable (int tag, merge_kind, tree decl, tree inner, tree type, + tree container, bool is_mod); + unsigned binfo_mergeable (tree *); + +private: + uintptr_t *find_duplicate (tree existing); + void register_duplicate (tree decl, tree existing); + /* Mark as an already diagnosed bad duplicate. */ + void unmatched_duplicate (tree existing) + { + *find_duplicate (existing) |= 1; + } + +public: + bool is_duplicate (tree decl) + { + return find_duplicate (decl) != NULL; + } + tree maybe_duplicate (tree decl) + { + if (uintptr_t *dup = find_duplicate (decl)) + return reinterpret_cast<tree> (*dup & ~uintptr_t (1)); + return decl; + } + tree odr_duplicate (tree decl, bool has_defn); + +public: + /* Return the next decl to postprocess, or NULL. */ + tree post_process () + { + return post_decls.length () ? post_decls.pop () : NULL_TREE; + } +private: + /* Register DECL for postprocessing. */ + void post_process (tree decl) + { + post_decls.safe_push (decl); + } + +private: + void assert_definition (tree, bool installing); +}; + +trees_in::trees_in (module_state *state) + :parent (), state (state), unused (0) +{ + duplicates = NULL; + back_refs.create (500); + post_decls.create (0); +} + +trees_in::~trees_in () +{ + delete (duplicates); + back_refs.release (); + post_decls.release (); +} + +/* Tree stream writer. */ +class trees_out : public bytes_out { + typedef bytes_out parent; + +private: + module_state *state; /* The module we are writing. */ + ptr_int_hash_map tree_map; /* Trees to references */ + depset::hash *dep_hash; /* Dependency table. */ + int ref_num; /* Back reference number. */ + unsigned section; +#if CHECKING_P + int importedness; /* Checker that imports not occurring + inappropriately. */ +#endif + +public: + trees_out (allocator *, module_state *, depset::hash &deps, unsigned sec = 0); + ~trees_out (); + +private: + void mark_trees (); + void unmark_trees (); + +public: + /* Hey, let's ignore the well known STL iterator idiom. */ + void begin (); + unsigned end (elf_out *sink, unsigned name, unsigned *crc_ptr); + void end (); + +public: + enum tags + { + tag_backref = -1, /* Upper bound on the backrefs. */ + tag_value = 0, /* Write by value. */ + tag_fixed /* Lower bound on the fixed trees. */ + }; + +public: + bool is_key_order () const + { + return dep_hash->is_key_order (); + } + +public: + int insert (tree, walk_kind = WK_normal); + +private: + void start (tree, bool = false); + +private: + walk_kind ref_node (tree); +public: + int get_tag (tree); + void set_importing (int i ATTRIBUTE_UNUSED) + { +#if CHECKING_P + importedness = i; +#endif + } + +private: + void core_bools (tree); + void core_vals (tree); + void lang_type_bools (tree); + void lang_type_vals (tree); + void lang_decl_bools (tree); + void lang_decl_vals (tree); + void lang_vals (tree); + void tree_node_bools (tree); + void tree_node_vals (tree); + +private: + void chained_decls (tree); + void vec_chained_decls (tree); + void tree_vec (vec<tree, va_gc> *); + void tree_pair_vec (vec<tree_pair_s, va_gc> *); + void tree_list (tree, bool has_purpose); + +public: + /* Mark a node for by-value walking. */ + void mark_by_value (tree); + +public: + void tree_node (tree); + +private: + void install_entity (tree decl, depset *); + void tpl_parms (tree parms, unsigned &tpl_levels); + void tpl_parms_fini (tree decl, unsigned tpl_levels); + void fn_parms_fini (tree) {} + unsigned add_indirect_tpl_parms (tree); +public: + void add_indirects (tree); + void fn_parms_init (tree); + void tpl_header (tree decl, unsigned *tpl_levels); + +public: + merge_kind get_merge_kind (tree decl, depset *maybe_dep); + tree decl_container (tree decl); + void key_mergeable (int tag, merge_kind, tree decl, tree inner, + tree container, depset *maybe_dep); + void binfo_mergeable (tree binfo); + +private: + bool decl_node (tree, walk_kind ref); + void type_node (tree); + void tree_value (tree); + void tpl_parm_value (tree); + +public: + void decl_value (tree, depset *); + +public: + /* Serialize various definitions. */ + void write_definition (tree decl); + void mark_declaration (tree decl, bool do_defn); + +private: + void mark_function_def (tree decl); + void mark_var_def (tree decl); + void mark_class_def (tree decl); + void mark_enum_def (tree decl); + void mark_class_member (tree decl, bool do_defn = true); + void mark_binfos (tree type); + +private: + void write_var_def (tree decl); + void write_function_def (tree decl); + void write_class_def (tree decl); + void write_enum_def (tree decl); + +private: + static void assert_definition (tree); + +public: + static void instrument (); + +private: + /* Tree instrumentation. */ + static unsigned tree_val_count; + static unsigned decl_val_count; + static unsigned back_ref_count; + static unsigned null_count; +}; + +/* Instrumentation counters. */ +unsigned trees_out::tree_val_count; +unsigned trees_out::decl_val_count; +unsigned trees_out::back_ref_count; +unsigned trees_out::null_count; + +trees_out::trees_out (allocator *mem, module_state *state, depset::hash &deps, + unsigned section) + :parent (mem), state (state), tree_map (500), + dep_hash (&deps), ref_num (0), section (section) +{ +#if CHECKING_P + importedness = 0; +#endif +} + +trees_out::~trees_out () +{ +} + +/********************************************************************/ +/* Location. We're aware of the line-map concept and reproduce it + here. Each imported module allocates a contiguous span of ordinary + maps, and of macro maps. adhoc maps are serialized by contents, + not pre-allocated. The scattered linemaps of a module are + coalesced when writing. */ + + +/* I use half-open [first,second) ranges. */ +typedef std::pair<unsigned,unsigned> range_t; + +/* A range of locations. */ +typedef std::pair<location_t,location_t> loc_range_t; + +/* Spans of the line maps that are occupied by this TU. I.e. not + within imports. Only extended when in an interface unit. + Interval zero corresponds to the forced header linemap(s). This + is a singleton object. */ + +class loc_spans { +public: + /* An interval of line maps. The line maps here represent a contiguous + non-imported range. */ + struct span { + loc_range_t ordinary; /* Ordinary map location range. */ + loc_range_t macro; /* Macro map location range. */ + int ordinary_delta; /* Add to ordinary loc to get serialized loc. */ + int macro_delta; /* Likewise for macro loc. */ + }; + +private: + vec<span> *spans; + +public: + loc_spans () + /* Do not preallocate spans, as that causes + --enable-detailed-mem-stats problems. */ + : spans (nullptr) + { + } + ~loc_spans () + { + delete spans; + } + +public: + span &operator[] (unsigned ix) + { + return (*spans)[ix]; + } + unsigned length () const + { + return spans->length (); + } + +public: + bool init_p () const + { + return spans != nullptr; + } + /* Initializer. */ + void init (const line_maps *lmaps, const line_map_ordinary *map); + + /* Slightly skewed preprocessed files can cause us to miss an + initialization in some places. Fallback initializer. */ + void maybe_init () + { + if (!init_p ()) + init (line_table, nullptr); + } + +public: + enum { + SPAN_RESERVED = 0, /* Reserved (fixed) locations. */ + SPAN_FIRST = 1, /* LWM of locations to stream */ + SPAN_MAIN = 2 /* Main file and onwards. */ + }; + +public: + location_t main_start () const + { + return (*spans)[SPAN_MAIN].ordinary.first; + } + +public: + void open (location_t); + void close (); + +public: + /* Propagate imported linemaps to us, if needed. */ + bool maybe_propagate (module_state *import, location_t loc); + +public: + const span *ordinary (location_t); + const span *macro (location_t); +}; + +static loc_spans spans; + +/********************************************************************/ +/* Data needed by a module during the process of loading. */ +struct GTY(()) slurping { + + /* Remap import's module numbering to our numbering. Values are + shifted by 1. Bit0 encodes if the import is direct. */ + vec<unsigned, va_heap, vl_embed> * + GTY((skip)) remap; /* Module owner remapping. */ + + elf_in *GTY((skip)) from; /* The elf loader. */ + + /* This map is only for header imports themselves -- the global + headers bitmap hold it for the current TU. */ + bitmap headers; /* Transitive set of direct imports, including + self. Used for macro visibility and + priority. */ + + /* These objects point into the mmapped area, unless we're not doing + that, or we got frozen or closed. In those cases they point to + buffers we own. */ + bytes_in macro_defs; /* Macro definitions. */ + bytes_in macro_tbl; /* Macro table. */ + + /* Location remapping. first->ordinary, second->macro. */ + range_t GTY((skip)) loc_deltas; + + unsigned current; /* Section currently being loaded. */ + unsigned remaining; /* Number of lazy sections yet to read. */ + unsigned lru; /* An LRU counter. */ + + public: + slurping (elf_in *); + ~slurping (); + + public: + /* Close the ELF file, if it's open. */ + void close () + { + if (from) + { + from->end (); + delete from; + from = NULL; + } + } + + public: + void release_macros (); + + public: + void alloc_remap (unsigned size) + { + gcc_assert (!remap); + vec_safe_reserve (remap, size); + for (unsigned ix = size; ix--;) + remap->quick_push (0); + } + unsigned remap_module (unsigned owner) + { + if (owner < remap->length ()) + return (*remap)[owner] >> 1; + return 0; + } + + public: + /* GC allocation. But we must explicitly delete it. */ + static void *operator new (size_t x) + { + return ggc_alloc_atomic (x); + } + static void operator delete (void *p) + { + ggc_free (p); + } +}; + +slurping::slurping (elf_in *from) + : remap (NULL), from (from), + headers (BITMAP_GGC_ALLOC ()), macro_defs (), macro_tbl (), + loc_deltas (0, 0), + current (~0u), remaining (0), lru (0) +{ +} + +slurping::~slurping () +{ + vec_free (remap); + remap = NULL; + release_macros (); + close (); +} + +void slurping::release_macros () +{ + if (macro_defs.size) + elf_in::release (from, macro_defs); + if (macro_tbl.size) + elf_in::release (from, macro_tbl); +} + +/* Information about location maps used during writing. */ + +struct location_map_info { + range_t num_maps; + + unsigned max_range; +}; + +/* Flage for extensions that end up being streamed. */ + +enum streamed_extensions { + SE_OPENMP = 1 << 0, + SE_BITS = 1 +}; + +/********************************************************************/ +struct module_state_config; + +/* Increasing levels of loadedness. */ +enum module_loadedness { + ML_NONE, /* Not loaded. */ + ML_CONFIG, /* Config loaed. */ + ML_PREPROCESSOR, /* Preprocessor loaded. */ + ML_LANGUAGE, /* Language loaded. */ +}; + +/* Increasing levels of directness (toplevel) of import. */ +enum module_directness { + MD_NONE, /* Not direct. */ + MD_PARTITION_DIRECT, /* Direct import of a partition. */ + MD_DIRECT, /* Direct import. */ + MD_PURVIEW_DIRECT, /* direct import in purview. */ +}; + +/* State of a particular module. */ + +class GTY((chain_next ("%h.parent"), for_user)) module_state { + public: + /* We always import & export ourselves. */ + bitmap imports; /* Transitive modules we're importing. */ + bitmap exports; /* Subset of that, that we're exporting. */ + + module_state *parent; + tree name; /* Name of the module. */ + + slurping *slurp; /* Data for loading. */ + + const char *flatname; /* Flatname of module. */ + char *filename; /* CMI Filename */ + + /* Indices into the entity_ary. */ + unsigned entity_lwm; + unsigned entity_num; + + /* Location ranges for this module. adhoc-locs are decomposed, so + don't have a range. */ + loc_range_t GTY((skip)) ordinary_locs; + loc_range_t GTY((skip)) macro_locs; + + /* LOC is first set too the importing location. When initially + loaded it refers to a module loc whose parent is the importing + location. */ + location_t loc; /* Location referring to module itself. */ + unsigned crc; /* CRC we saw reading it in. */ + + unsigned mod; /* Module owner number. */ + unsigned remap; /* Remapping during writing. */ + + unsigned short subst; /* Mangle subst if !0. */ + + /* How loaded this module is. */ + enum module_loadedness loadedness : 2; + + bool module_p : 1; /* /The/ module of this TU. */ + bool header_p : 1; /* Is a header unit. */ + bool interface_p : 1; /* An interface. */ + bool partition_p : 1; /* A partition. */ + + /* How directly this module is imported. */ + enum module_directness directness : 2; + + bool exported_p : 1; /* directness != MD_NONE && exported. */ + bool cmi_noted_p : 1; /* We've told the user about the CMI, don't + do it again */ + bool call_init_p : 1; /* This module's global initializer needs + calling. */ + /* Record extensions emitted or permitted. */ + unsigned extensions : SE_BITS; + /* 12 bits used, 4 bits remain */ + + public: + module_state (tree name, module_state *, bool); + ~module_state (); + + public: + void release () + { + imports = exports = NULL; + slurped (); + } + void slurped () + { + delete slurp; + slurp = NULL; + } + elf_in *from () const + { + return slurp->from; + } + + public: + /* Kind of this module. */ + bool is_module () const + { + return module_p; + } + bool is_header () const + { + return header_p; + } + bool is_interface () const + { + return interface_p; + } + bool is_partition () const + { + return partition_p; + } + + /* How this module is used in the current TU. */ + bool is_exported () const + { + return exported_p; + } + bool is_direct () const + { + return directness >= MD_DIRECT; + } + bool is_purview_direct () const + { + return directness == MD_PURVIEW_DIRECT; + } + bool is_partition_direct () const + { + return directness == MD_PARTITION_DIRECT; + } + + public: + /* Is this not a real module? */ + bool is_rooted () const + { + return loc != UNKNOWN_LOCATION; + } + + public: + bool check_not_purview (location_t loc); + + public: + void mangle (bool include_partition); + + public: + void set_import (module_state const *, bool is_export); + void announce (const char *) const; + + public: + /* Read and write module. */ + void write (elf_out *to, cpp_reader *); + bool read_initial (cpp_reader *); + bool read_preprocessor (bool); + bool read_language (bool); + + public: + /* Read a section. */ + bool load_section (unsigned snum, binding_slot *mslot); + /* Lazily read a section. */ + bool lazy_load (unsigned index, binding_slot *mslot); + + public: + /* Juggle a limited number of file numbers. */ + static void freeze_an_elf (); + bool maybe_defrost (); + + public: + void maybe_completed_reading (); + bool check_read (bool outermost, bool ok); + + private: + /* The README, for human consumption. */ + void write_readme (elf_out *to, cpp_reader *, + const char *dialect, unsigned extensions); + void write_env (elf_out *to); + + private: + /* Import tables. */ + void write_imports (bytes_out &cfg, bool direct); + unsigned read_imports (bytes_in &cfg, cpp_reader *, line_maps *maps); + + private: + void write_imports (elf_out *to, unsigned *crc_ptr); + bool read_imports (cpp_reader *, line_maps *); + + private: + void write_partitions (elf_out *to, unsigned, unsigned *crc_ptr); + bool read_partitions (unsigned); + + private: + void write_config (elf_out *to, struct module_state_config &, unsigned crc); + bool read_config (struct module_state_config &); + static void write_counts (elf_out *to, unsigned [], unsigned *crc_ptr); + bool read_counts (unsigned []); + + public: + void note_cmi_name (); + + private: + static unsigned write_bindings (elf_out *to, vec<depset *> depsets, + unsigned *crc_ptr); + bool read_bindings (unsigned count, unsigned lwm, unsigned hwm); + + static void write_namespace (bytes_out &sec, depset *ns_dep); + tree read_namespace (bytes_in &sec); + + void write_namespaces (elf_out *to, vec<depset *> spaces, + unsigned, unsigned *crc_ptr); + bool read_namespaces (unsigned); + + unsigned write_cluster (elf_out *to, depset *depsets[], unsigned size, + depset::hash &, unsigned *counts, unsigned *crc_ptr); + bool read_cluster (unsigned snum); + + private: + unsigned write_inits (elf_out *to, depset::hash &, unsigned *crc_ptr); + bool read_inits (unsigned count); + + private: + void write_pendings (elf_out *to, vec<depset *> depsets, + depset::hash &, unsigned count, unsigned *crc_ptr); + bool read_pendings (unsigned count); + + private: + void write_entities (elf_out *to, vec<depset *> depsets, + unsigned count, unsigned *crc_ptr); + bool read_entities (unsigned count, unsigned lwm, unsigned hwm); + + private: + location_map_info write_prepare_maps (module_state_config *); + bool read_prepare_maps (const module_state_config *); + + void write_ordinary_maps (elf_out *to, location_map_info &, + module_state_config *, bool, unsigned *crc_ptr); + bool read_ordinary_maps (); + void write_macro_maps (elf_out *to, location_map_info &, + module_state_config *, unsigned *crc_ptr); + bool read_macro_maps (); + + private: + void write_define (bytes_out &, const cpp_macro *, bool located = true); + cpp_macro *read_define (bytes_in &, cpp_reader *, bool located = true) const; + unsigned write_macros (elf_out *to, cpp_reader *, unsigned *crc_ptr); + bool read_macros (); + void install_macros (); + + public: + void import_macros (); + + public: + static void undef_macro (cpp_reader *, location_t, cpp_hashnode *); + static cpp_macro *deferred_macro (cpp_reader *, location_t, cpp_hashnode *); + + public: + static void write_location (bytes_out &, location_t); + location_t read_location (bytes_in &) const; + + public: + void set_flatname (); + const char *get_flatname () const + { + return flatname; + } + location_t imported_from () const; + + public: + void set_filename (const Cody::Packet &); + bool do_import (cpp_reader *, bool outermost); +}; + +/* Hash module state by name. This cannot be a member of + module_state, because of GTY restrictions. We never delete from + the hash table, but ggc_ptr_hash doesn't support that + simplification. */ + +struct module_state_hash : ggc_ptr_hash<module_state> { + typedef std::pair<tree,uintptr_t> compare_type; /* {name,parent} */ + + static inline hashval_t hash (const value_type m); + static inline hashval_t hash (const compare_type &n); + static inline bool equal (const value_type existing, + const compare_type &candidate); +}; + +module_state::module_state (tree name, module_state *parent, bool partition) + : imports (BITMAP_GGC_ALLOC ()), exports (BITMAP_GGC_ALLOC ()), + parent (parent), name (name), slurp (NULL), + flatname (NULL), filename (NULL), + entity_lwm (~0u >> 1), entity_num (0), + ordinary_locs (0, 0), macro_locs (0, 0), + loc (UNKNOWN_LOCATION), + crc (0), mod (MODULE_UNKNOWN), remap (0), subst (0) +{ + loadedness = ML_NONE; + + module_p = header_p = interface_p = partition_p = false; + + directness = MD_NONE; + exported_p = false; + + cmi_noted_p = false; + call_init_p = false; + + partition_p = partition; + + extensions = 0; + if (name && TREE_CODE (name) == STRING_CST) + { + header_p = true; + + const char *string = TREE_STRING_POINTER (name); + gcc_checking_assert (string[0] == '.' + ? IS_DIR_SEPARATOR (string[1]) + : IS_ABSOLUTE_PATH (string)); + } + + gcc_checking_assert (!(parent && header_p)); +} + +module_state::~module_state () +{ + release (); +} + +/* Hash module state. */ +static hashval_t +module_name_hash (const_tree name) +{ + if (TREE_CODE (name) == STRING_CST) + return htab_hash_string (TREE_STRING_POINTER (name)); + else + return IDENTIFIER_HASH_VALUE (name); +} + +hashval_t +module_state_hash::hash (const value_type m) +{ + hashval_t ph = pointer_hash<void>::hash + (reinterpret_cast<void *> (reinterpret_cast<uintptr_t> (m->parent) + | m->is_partition ())); + hashval_t nh = module_name_hash (m->name); + return iterative_hash_hashval_t (ph, nh); +} + +/* Hash a name. */ +hashval_t +module_state_hash::hash (const compare_type &c) +{ + hashval_t ph = pointer_hash<void>::hash (reinterpret_cast<void *> (c.second)); + hashval_t nh = module_name_hash (c.first); + + return iterative_hash_hashval_t (ph, nh); +} + +bool +module_state_hash::equal (const value_type existing, + const compare_type &candidate) +{ + uintptr_t ep = (reinterpret_cast<uintptr_t> (existing->parent) + | existing->is_partition ()); + if (ep != candidate.second) + return false; + + /* Identifier comparison is by pointer. If the string_csts happen + to be the same object, then they're equal too. */ + if (existing->name == candidate.first) + return true; + + /* If neither are string csts, they can't be equal. */ + if (TREE_CODE (candidate.first) != STRING_CST + || TREE_CODE (existing->name) != STRING_CST) + return false; + + /* String equality. */ + if (TREE_STRING_LENGTH (existing->name) + == TREE_STRING_LENGTH (candidate.first) + && !memcmp (TREE_STRING_POINTER (existing->name), + TREE_STRING_POINTER (candidate.first), + TREE_STRING_LENGTH (existing->name))) + return true; + + return false; +} + +/********************************************************************/ +/* Global state */ + +/* Mapper name. */ +static const char *module_mapper_name; + +/* CMI repository path and workspace. */ +static char *cmi_repo; +static size_t cmi_repo_length; +static char *cmi_path; +static size_t cmi_path_alloc; + +/* Count of available and loaded clusters. */ +static unsigned available_clusters; +static unsigned loaded_clusters; + +/* What the current TU is. */ +unsigned module_kind; + +/* Number of global init calls needed. */ +unsigned num_init_calls_needed = 0; + +/* Global trees. */ +static const std::pair<tree *, unsigned> global_tree_arys[] = + { + std::pair<tree *, unsigned> (sizetype_tab, stk_type_kind_last), + std::pair<tree *, unsigned> (integer_types, itk_none), + std::pair<tree *, unsigned> (global_trees, TI_MODULE_HWM), + std::pair<tree *, unsigned> (c_global_trees, CTI_MODULE_HWM), + std::pair<tree *, unsigned> (cp_global_trees, CPTI_MODULE_HWM), + std::pair<tree *, unsigned> (NULL, 0) + }; +static GTY(()) vec<tree, va_gc> *fixed_trees; +static unsigned global_crc; + +/* Lazy loading can open many files concurrently, there are + per-process limits on that. We pay attention to the process limit, + and attempt to increase it when we run out. Otherwise we use an + LRU scheme to figure out who to flush. Note that if the import + graph /depth/ exceeds lazy_limit, we'll exceed the limit. */ +static unsigned lazy_lru; /* LRU counter. */ +static unsigned lazy_open; /* Number of open modules */ +static unsigned lazy_limit; /* Current limit of open modules. */ +static unsigned lazy_hard_limit; /* Hard limit on open modules. */ +/* Account for source, assembler and dump files & directory searches. + We don't keep the source file's open, so we don't have to account + for #include depth. I think dump files are opened and closed per + pass, but ICBW. */ +#define LAZY_HEADROOM 15 /* File descriptor headroom. */ + +/* Vector of module state. Indexed by OWNER. Has at least 2 slots. */ +static GTY(()) vec<module_state *, va_gc> *modules; + +/* Hash of module state, findable by {name, parent}. */ +static GTY(()) hash_table<module_state_hash> *modules_hash; + +/* Map of imported entities. We map DECL_UID to index of entity + vector. */ +typedef hash_map<unsigned/*UID*/, unsigned/*index*/, + simple_hashmap_traits<int_hash<unsigned,0>, unsigned> + > entity_map_t; +static entity_map_t *entity_map; +/* Doesn't need GTYing, because any tree referenced here is also + findable by, symbol table, specialization table, return type of + reachable function. */ +static vec<binding_slot, va_heap, vl_embed> *entity_ary; + +/* Members entities of imported classes that are defined in this TU. + These are where the entity's context is not from the current TU. + We need to emit the definition (but not the enclosing class). + + We could find these by walking ALL the imported classes that we + could provide a member definition. But that's expensive, + especially when you consider lazy implicit member declarations, + which could be ANY imported class. */ +static GTY(()) vec<tree, va_gc> *class_members; + +/* The same problem exists for class template partial + specializations. Now that we have constraints, the invariant of + expecting them in the instantiation table no longer holds. One of + the constrained partial specializations will be there, but the + others not so much. It's not even an unconstrained partial + spacialization in the table :( so any partial template declaration + is added to this list too. */ +static GTY(()) vec<tree, va_gc> *partial_specializations; + +/********************************************************************/ + +/* Our module mapper (created lazily). */ +module_client *mapper; + +static module_client *make_mapper (location_t loc); +inline module_client *get_mapper (location_t loc) +{ + auto *res = mapper; + if (!res) + res = make_mapper (loc); + return res; +} + +/********************************************************************/ +static tree +get_clone_target (tree decl) +{ + tree target; + + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree res_orig = DECL_CLONED_FUNCTION (DECL_TEMPLATE_RESULT (decl)); + + target = DECL_TI_TEMPLATE (res_orig); + } + else + target = DECL_CLONED_FUNCTION (decl); + + gcc_checking_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (target)); + + return target; +} + +/* Like FOR_EACH_CLONE, but will walk cloned templates. */ +#define FOR_EVERY_CLONE(CLONE, FN) \ + if (!DECL_MAYBE_IN_CHARGE_CDTOR_P (FN)); \ + else \ + for (CLONE = DECL_CHAIN (FN); \ + CLONE && DECL_CLONED_FUNCTION_P (CLONE); \ + CLONE = DECL_CHAIN (CLONE)) + +/* It'd be nice if USE_TEMPLATE was a field of template_info + (a) it'd solve the enum case dealt with below, + (b) both class templates and decl templates would store this in the + same place + (c) this function wouldn't need the by-ref arg, which is annoying. */ + +static tree +node_template_info (tree decl, int &use) +{ + tree ti = NULL_TREE; + int use_tpl = -1; + if (DECL_IMPLICIT_TYPEDEF_P (decl)) + { + tree type = TREE_TYPE (decl); + + ti = TYPE_TEMPLATE_INFO (type); + if (ti) + { + if (TYPE_LANG_SPECIFIC (type)) + use_tpl = CLASSTYPE_USE_TEMPLATE (type); + else + { + /* An enum, where we don't explicitly encode use_tpl. + If the containing context (a type or a function), is + an ({im,ex}plicit) instantiation, then this is too. + If it's a partial or explicit specialization, then + this is not!. */ + tree ctx = CP_DECL_CONTEXT (decl); + if (TYPE_P (ctx)) + ctx = TYPE_NAME (ctx); + node_template_info (ctx, use); + use_tpl = use != 2 ? use : 0; + } + } + } + else if (DECL_LANG_SPECIFIC (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == TEMPLATE_DECL)) + { + use_tpl = DECL_USE_TEMPLATE (decl); + ti = DECL_TEMPLATE_INFO (decl); + } + + use = use_tpl; + return ti; +} + +/* Find the index in entity_ary for an imported DECL. It should + always be there, but bugs can cause it to be missing, and that can + crash the crash reporting -- let's not do that! When streaming + out we place entities from this module there too -- with negated + indices. */ + +static unsigned +import_entity_index (tree decl, bool null_ok = false) +{ + if (unsigned *slot = entity_map->get (DECL_UID (decl))) + return *slot; + + gcc_checking_assert (null_ok); + return ~(~0u >> 1); +} + +/* Find the module for an imported entity at INDEX in the entity ary. + There must be one. */ + +static module_state * +import_entity_module (unsigned index) +{ + if (index > ~(~0u >> 1)) + /* This is an index for an exported entity. */ + return (*modules)[0]; + + /* Do not include the current TU (not an off-by-one error). */ + unsigned pos = 1; + unsigned len = modules->length () - pos; + while (len) + { + unsigned half = len / 2; + module_state *probe = (*modules)[pos + half]; + if (index < probe->entity_lwm) + len = half; + else if (index < probe->entity_lwm + probe->entity_num) + return probe; + else + { + pos += half + 1; + len = len - (half + 1); + } + } + gcc_unreachable (); +} + + +/********************************************************************/ +/* A dumping machinery. */ + +class dumper { +public: + enum { + LOCATION = TDF_LINENO, /* -lineno:Source location streaming. */ + DEPEND = TDF_GRAPH, /* -graph:Dependency graph construction. */ + CLUSTER = TDF_BLOCKS, /* -blocks:Clusters. */ + TREE = TDF_UID, /* -uid:Tree streaming. */ + MERGE = TDF_ALIAS, /* -alias:Mergeable Entities. */ + ELF = TDF_ASMNAME, /* -asmname:Elf data. */ + MACRO = TDF_VOPS /* -vops:Macros. */ + }; + +private: + struct impl { + typedef vec<module_state *, va_heap, vl_embed> stack_t; + + FILE *stream; /* Dump stream. */ + unsigned indent; /* Local indentation. */ + bool bol; /* Beginning of line. */ + stack_t stack; /* Trailing array of module_state. */ + + bool nested_name (tree); /* Dump a name following DECL_CONTEXT. */ + }; + +public: + /* The dumper. */ + impl *dumps; + dump_flags_t flags; + +public: + /* Push/pop module state dumping. */ + unsigned push (module_state *); + void pop (unsigned); + +public: + /* Change local indentation. */ + void indent () + { + if (dumps) + dumps->indent++; + } + void outdent () + { + if (dumps) + { + gcc_checking_assert (dumps->indent); + dumps->indent--; + } + } + +public: + /* Is dump enabled?. */ + bool operator () (int mask = 0) + { + if (!dumps || !dumps->stream) + return false; + if (mask && !(mask & flags)) + return false; + return true; + } + /* Dump some information. */ + bool operator () (const char *, ...); +}; + +/* The dumper. */ +static dumper dump = {0, dump_flags_t (0)}; + +/* Push to dumping M. Return previous indentation level. */ + +unsigned +dumper::push (module_state *m) +{ + FILE *stream = NULL; + if (!dumps || !dumps->stack.length ()) + { + stream = dump_begin (module_dump_id, &flags); + if (!stream) + return 0; + } + + if (!dumps || !dumps->stack.space (1)) + { + /* Create or extend the dump implementor. */ + unsigned current = dumps ? dumps->stack.length () : 0; + unsigned count = current ? current * 2 : EXPERIMENT (1, 20); + size_t alloc = (offsetof (impl, stack) + + impl::stack_t::embedded_size (count)); + dumps = XRESIZEVAR (impl, dumps, alloc); + dumps->stack.embedded_init (count, current); + } + if (stream) + dumps->stream = stream; + + unsigned n = dumps->indent; + dumps->indent = 0; + dumps->bol = true; + dumps->stack.quick_push (m); + if (m) + { + module_state *from = NULL; + + if (dumps->stack.length () > 1) + from = dumps->stack[dumps->stack.length () - 2]; + else + dump (""); + dump (from ? "Starting module %M (from %M)" + : "Starting module %M", m, from); + } + + return n; +} + +/* Pop from dumping. Restore indentation to N. */ + +void dumper::pop (unsigned n) +{ + if (!dumps) + return; + + gcc_checking_assert (dump () && !dumps->indent); + if (module_state *m = dumps->stack[dumps->stack.length () - 1]) + { + module_state *from = (dumps->stack.length () > 1 + ? dumps->stack[dumps->stack.length () - 2] : NULL); + dump (from ? "Finishing module %M (returning to %M)" + : "Finishing module %M", m, from); + } + dumps->stack.pop (); + dumps->indent = n; + if (!dumps->stack.length ()) + { + dump_end (module_dump_id, dumps->stream); + dumps->stream = NULL; + } +} + +/* Dump a nested name for arbitrary tree T. Sometimes it won't have a + name. */ + +bool +dumper::impl::nested_name (tree t) +{ + tree ti = NULL_TREE; + int origin = -1; + tree name = NULL_TREE; + + if (t && TREE_CODE (t) == TREE_BINFO) + t = BINFO_TYPE (t); + + if (t && TYPE_P (t)) + t = TYPE_NAME (t); + + if (t && DECL_P (t)) + { + if (t == global_namespace || DECL_TEMPLATE_PARM_P (t)) + ; + else if (tree ctx = DECL_CONTEXT (t)) + if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL + || nested_name (ctx)) + fputs ("::", stream); + + int use_tpl; + ti = node_template_info (t, use_tpl); + if (ti && TREE_CODE (TI_TEMPLATE (ti)) == TEMPLATE_DECL + && (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == t)) + t = TI_TEMPLATE (ti); + if (TREE_CODE (t) == TEMPLATE_DECL) + fputs ("template ", stream); + + if (DECL_LANG_SPECIFIC (t) && DECL_MODULE_IMPORT_P (t)) + { + /* We need to be careful here, so as to not explode on + inconsistent data -- we're probably debugging, because + Something Is Wrong. */ + unsigned index = import_entity_index (t, true); + if (!(index & ~(~0u >> 1))) + origin = import_entity_module (index)->mod; + else if (index > ~(~0u >> 1)) + /* An imported partition member that we're emitting. */ + origin = 0; + else + origin = -2; + } + + name = DECL_NAME (t) ? DECL_NAME (t) + : HAS_DECL_ASSEMBLER_NAME_P (t) ? DECL_ASSEMBLER_NAME_RAW (t) + : NULL_TREE; + } + else + name = t; + + if (name) + switch (TREE_CODE (name)) + { + default: + fputs ("#unnamed#", stream); + break; + + case IDENTIFIER_NODE: + fwrite (IDENTIFIER_POINTER (name), 1, IDENTIFIER_LENGTH (name), stream); + break; + + case INTEGER_CST: + print_hex (wi::to_wide (name), stream); + break; + + case STRING_CST: + /* If TREE_TYPE is NULL, this is a raw string. */ + fwrite (TREE_STRING_POINTER (name), 1, + TREE_STRING_LENGTH (name) - (TREE_TYPE (name) != NULL_TREE), + stream); + break; + } + else + fputs ("#null#", stream); + + if (origin >= 0) + { + const module_state *module = (*modules)[origin]; + fprintf (stream, "@%s:%d", !module ? "" : !module->name ? "(unnamed)" + : module->get_flatname (), origin); + } + else if (origin == -2) + fprintf (stream, "@???"); + + if (ti) + { + tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti)); + fputs ("<", stream); + if (args) + for (int ix = 0; ix != TREE_VEC_LENGTH (args); ix++) + { + if (ix) + fputs (",", stream); + nested_name (TREE_VEC_ELT (args, ix)); + } + fputs (">", stream); + } + + return true; +} + +/* Formatted dumping. FORMAT begins with '+' do not emit a trailing + new line. (Normally it is appended.) + Escapes: + %C - tree_code + %I - identifier + %M - module_state + %N - name -- DECL_NAME + %P - context:name pair + %R - unsigned:unsigned ratio + %S - symbol -- DECL_ASSEMBLER_NAME + %U - long unsigned + %V - version + --- the following are printf-like, but without its flexibility + %d - decimal int + %p - pointer + %s - string + %u - unsigned int + %x - hex int + + We do not implement the printf modifiers. */ + +bool +dumper::operator () (const char *format, ...) +{ + if (!(*this) ()) + return false; + + bool no_nl = format[0] == '+'; + format += no_nl; + + if (dumps->bol) + { + /* Module import indent. */ + if (unsigned depth = dumps->stack.length () - 1) + { + const char *prefix = ">>>>"; + fprintf (dumps->stream, (depth <= strlen (prefix) + ? &prefix[strlen (prefix) - depth] + : ">.%d.>"), depth); + } + + /* Local indent. */ + if (unsigned indent = dumps->indent) + { + const char *prefix = " "; + fprintf (dumps->stream, (indent <= strlen (prefix) + ? &prefix[strlen (prefix) - indent] + : " .%d. "), indent); + } + dumps->bol = false; + } + + va_list args; + va_start (args, format); + while (const char *esc = strchr (format, '%')) + { + fwrite (format, 1, (size_t)(esc - format), dumps->stream); + format = ++esc; + switch (*format++) + { + default: + gcc_unreachable (); + + case '%': + fputc ('%', dumps->stream); + break; + + case 'C': /* Code */ + { + tree_code code = (tree_code)va_arg (args, unsigned); + fputs (get_tree_code_name (code), dumps->stream); + } + break; + + case 'I': /* Identifier. */ + { + tree t = va_arg (args, tree); + dumps->nested_name (t); + } + break; + + case 'M': /* Module. */ + { + const char *str = "(none)"; + if (module_state *m = va_arg (args, module_state *)) + { + if (!m->is_rooted ()) + str = "(detached)"; + else + str = m->get_flatname (); + } + fputs (str, dumps->stream); + } + break; + + case 'N': /* Name. */ + { + tree t = va_arg (args, tree); + if (t && TREE_CODE (t) == OVERLOAD) + t = OVL_FIRST (t); + fputc ('\'', dumps->stream); + dumps->nested_name (t); + fputc ('\'', dumps->stream); + } + break; + + case 'P': /* Pair. */ + { + tree ctx = va_arg (args, tree); + tree name = va_arg (args, tree); + fputc ('\'', dumps->stream); + dumps->nested_name (ctx); + if (ctx && ctx != global_namespace) + fputs ("::", dumps->stream); + dumps->nested_name (name); + fputc ('\'', dumps->stream); + } + break; + + case 'R': /* Ratio */ + { + unsigned a = va_arg (args, unsigned); + unsigned b = va_arg (args, unsigned); + fprintf (dumps->stream, "%.1f", (float) a / (b + !b)); + } + break; + + case 'S': /* Symbol name */ + { + tree t = va_arg (args, tree); + if (t && TYPE_P (t)) + t = TYPE_NAME (t); + if (t && HAS_DECL_ASSEMBLER_NAME_P (t) + && DECL_ASSEMBLER_NAME_SET_P (t)) + { + fputc ('(', dumps->stream); + fputs (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t)), + dumps->stream); + fputc (')', dumps->stream); + } + } + break; + + case 'U': /* long unsigned. */ + { + unsigned long u = va_arg (args, unsigned long); + fprintf (dumps->stream, "%lu", u); + } + break; + + case 'V': /* Verson. */ + { + unsigned v = va_arg (args, unsigned); + verstr_t string; + + version2string (v, string); + fputs (string, dumps->stream); + } + break; + + case 'c': /* Character. */ + { + int c = va_arg (args, int); + fputc (c, dumps->stream); + } + break; + + case 'd': /* Decimal Int. */ + { + int d = va_arg (args, int); + fprintf (dumps->stream, "%d", d); + } + break; + + case 'p': /* Pointer. */ + { + void *p = va_arg (args, void *); + fprintf (dumps->stream, "%p", p); + } + break; + + case 's': /* String. */ + { + const char *s = va_arg (args, char *); + gcc_checking_assert (s); + fputs (s, dumps->stream); + } + break; + + case 'u': /* Unsigned. */ + { + unsigned u = va_arg (args, unsigned); + fprintf (dumps->stream, "%u", u); + } + break; + + case 'x': /* Hex. */ + { + unsigned x = va_arg (args, unsigned); + fprintf (dumps->stream, "%x", x); + } + break; + } + } + fputs (format, dumps->stream); + va_end (args); + if (!no_nl) + { + dumps->bol = true; + fputc ('\n', dumps->stream); + } + return true; +} + +struct note_def_cache_hasher : ggc_cache_ptr_hash<tree_node> +{ + static int keep_cache_entry (tree t) + { + if (!CHECKING_P) + /* GTY is unfortunately not clever enough to conditionalize + this. */ + gcc_unreachable (); + + if (ggc_marked_p (t)) + return -1; + + unsigned n = dump.push (NULL); + /* This might or might not be an error. We should note its + dropping whichever. */ + dump () && dump ("Dropping %N from note_defs table", t); + dump.pop (n); + + return 0; + } +}; + +/* We should stream each definition at most once. + This needs to be a cache because there are cases where a definition + ends up being not retained, and we need to drop those so we don't + get confused if memory is reallocated. */ +typedef hash_table<note_def_cache_hasher> note_defs_table_t; +static GTY((cache)) note_defs_table_t *note_defs; + +void +trees_in::assert_definition (tree decl ATTRIBUTE_UNUSED, + bool installing ATTRIBUTE_UNUSED) +{ +#if CHECKING_P + tree *slot = note_defs->find_slot (decl, installing ? INSERT : NO_INSERT); + if (installing) + { + /* We must be inserting for the first time. */ + gcc_assert (!*slot); + *slot = decl; + } + else + /* If this is not the mergeable entity, it should not be in the + table. If it is a non-global-module mergeable entity, it + should be in the table. Global module entities could have been + defined textually in the current TU and so might or might not + be present. */ + gcc_assert (!is_duplicate (decl) + ? !slot + : (slot + || !DECL_LANG_SPECIFIC (decl) + || !DECL_MODULE_PURVIEW_P (decl) + || (!DECL_MODULE_IMPORT_P (decl) + && header_module_p ()))); + + if (TREE_CODE (decl) == TEMPLATE_DECL) + gcc_assert (!note_defs->find_slot (DECL_TEMPLATE_RESULT (decl), NO_INSERT)); +#endif +} + +void +trees_out::assert_definition (tree decl ATTRIBUTE_UNUSED) +{ +#if CHECKING_P + tree *slot = note_defs->find_slot (decl, INSERT); + gcc_assert (!*slot); + *slot = decl; + if (TREE_CODE (decl) == TEMPLATE_DECL) + gcc_assert (!note_defs->find_slot (DECL_TEMPLATE_RESULT (decl), NO_INSERT)); +#endif +} + +/********************************************************************/ +static bool +noisy_p () +{ + if (quiet_flag) + return false; + + pp_needs_newline (global_dc->printer) = true; + diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL); + + return true; +} + +/* Set the cmi repo. Strip trailing '/', '.' becomes NULL. */ + +static void +set_cmi_repo (const char *r) +{ + XDELETEVEC (cmi_repo); + XDELETEVEC (cmi_path); + cmi_path_alloc = 0; + + cmi_repo = NULL; + cmi_repo_length = 0; + + if (!r || !r[0]) + return; + + size_t len = strlen (r); + cmi_repo = XNEWVEC (char, len + 1); + memcpy (cmi_repo, r, len + 1); + + if (len > 1 && IS_DIR_SEPARATOR (cmi_repo[len-1])) + len--; + if (len == 1 && cmi_repo[0] == '.') + len--; + cmi_repo[len] = 0; + cmi_repo_length = len; +} + +/* TO is a repo-relative name. Provide one that we may use from where + we are. */ + +static const char * +maybe_add_cmi_prefix (const char *to, size_t *len_p = NULL) +{ + size_t len = len_p || cmi_repo_length ? strlen (to) : 0; + + if (cmi_repo_length && !IS_ABSOLUTE_PATH (to)) + { + if (cmi_path_alloc < cmi_repo_length + len + 2) + { + XDELETEVEC (cmi_path); + cmi_path_alloc = cmi_repo_length + len * 2 + 2; + cmi_path = XNEWVEC (char, cmi_path_alloc); + + memcpy (cmi_path, cmi_repo, cmi_repo_length); + cmi_path[cmi_repo_length] = DIR_SEPARATOR; + } + + memcpy (&cmi_path[cmi_repo_length + 1], to, len + 1); + len += cmi_repo_length + 1; + to = cmi_path; + } + + if (len_p) + *len_p = len; + + return to; +} + +/* Try and create the directories of PATH. */ + +static void +create_dirs (char *path) +{ + /* Try and create the missing directories. */ + for (char *base = path; *base; base++) + if (IS_DIR_SEPARATOR (*base)) + { + char sep = *base; + *base = 0; + int failed = mkdir (path, S_IRWXU | S_IRWXG | S_IRWXO); + dump () && dump ("Mkdir ('%s') errno:=%u", path, failed ? errno : 0); + *base = sep; + if (failed + /* Maybe racing with another creator (of a *different* + module). */ + && errno != EEXIST) + break; + } +} + +/* Given a CLASSTYPE_DECL_LIST VALUE get the the template friend decl, + if that's what this is. */ + +static tree +friend_from_decl_list (tree frnd) +{ + tree res = frnd; + + if (TREE_CODE (frnd) != TEMPLATE_DECL) + { + tree tmpl = NULL_TREE; + if (TYPE_P (frnd)) + { + res = TYPE_NAME (frnd); + if (CLASSTYPE_TEMPLATE_INFO (frnd)) + tmpl = CLASSTYPE_TI_TEMPLATE (frnd); + } + else if (DECL_TEMPLATE_INFO (frnd)) + { + tmpl = DECL_TI_TEMPLATE (frnd); + if (TREE_CODE (tmpl) != TEMPLATE_DECL) + tmpl = NULL_TREE; + } + + if (tmpl && DECL_TEMPLATE_RESULT (tmpl) == res) + res = tmpl; + } + + return res; +} + +static tree +find_enum_member (tree ctx, tree name) +{ + for (tree values = TYPE_VALUES (ctx); + values; values = TREE_CHAIN (values)) + if (DECL_NAME (TREE_VALUE (values)) == name) + return TREE_VALUE (values); + + return NULL_TREE; +} + +/********************************************************************/ +/* Instrumentation gathered writing bytes. */ + +void +bytes_out::instrument () +{ + dump ("Wrote %u bytes in %u blocks", lengths[3], spans[3]); + dump ("Wrote %u bits in %u bytes", lengths[0] + lengths[1], lengths[2]); + for (unsigned ix = 0; ix < 2; ix++) + dump (" %u %s spans of %R bits", spans[ix], + ix ? "one" : "zero", lengths[ix], spans[ix]); + dump (" %u blocks with %R bits padding", spans[2], + lengths[2] * 8 - (lengths[0] + lengths[1]), spans[2]); +} + +/* Instrumentation gathered writing trees. */ +void +trees_out::instrument () +{ + if (dump ("")) + { + bytes_out::instrument (); + dump ("Wrote:"); + dump (" %u decl trees", decl_val_count); + dump (" %u other trees", tree_val_count); + dump (" %u back references", back_ref_count); + dump (" %u null trees", null_count); + } +} + +/* Setup and teardown for a tree walk. */ + +void +trees_out::begin () +{ + gcc_assert (!streaming_p () || !tree_map.elements ()); + + mark_trees (); + if (streaming_p ()) + parent::begin (); +} + +unsigned +trees_out::end (elf_out *sink, unsigned name, unsigned *crc_ptr) +{ + gcc_checking_assert (streaming_p ()); + + unmark_trees (); + return parent::end (sink, name, crc_ptr); +} + +void +trees_out::end () +{ + gcc_assert (!streaming_p ()); + + unmark_trees (); + /* Do not parent::end -- we weren't streaming. */ +} + +void +trees_out::mark_trees () +{ + if (size_t size = tree_map.elements ()) + { + /* This isn't our first rodeo, destroy and recreate the + tree_map. I'm a bad bad man. Use the previous size as a + guess for the next one (so not all bad). */ + tree_map.~ptr_int_hash_map (); + new (&tree_map) ptr_int_hash_map (size); + } + + /* Install the fixed trees, with +ve references. */ + unsigned limit = fixed_trees->length (); + for (unsigned ix = 0; ix != limit; ix++) + { + tree val = (*fixed_trees)[ix]; + bool existed = tree_map.put (val, ix + tag_fixed); + gcc_checking_assert (!TREE_VISITED (val) && !existed); + TREE_VISITED (val) = true; + } + + ref_num = 0; +} + +/* Unmark the trees we encountered */ + +void +trees_out::unmark_trees () +{ + ptr_int_hash_map::iterator end (tree_map.end ()); + for (ptr_int_hash_map::iterator iter (tree_map.begin ()); iter != end; ++iter) + { + tree node = reinterpret_cast<tree> ((*iter).first); + int ref = (*iter).second; + /* We should have visited the node, and converted its mergeable + reference to a regular reference. */ + gcc_checking_assert (TREE_VISITED (node) + && (ref <= tag_backref || ref >= tag_fixed)); + TREE_VISITED (node) = false; + } +} + +/* Mark DECL for by-value walking. We do this by inserting it into + the tree map with a reference of zero. May be called multiple + times on the same node. */ + +void +trees_out::mark_by_value (tree decl) +{ + gcc_checking_assert (DECL_P (decl) + /* Enum consts are INTEGER_CSTS. */ + || TREE_CODE (decl) == INTEGER_CST + || TREE_CODE (decl) == TREE_BINFO); + + if (TREE_VISITED (decl)) + /* Must already be forced or fixed. */ + gcc_checking_assert (*tree_map.get (decl) >= tag_value); + else + { + bool existed = tree_map.put (decl, tag_value); + gcc_checking_assert (!existed); + TREE_VISITED (decl) = true; + } +} + +int +trees_out::get_tag (tree t) +{ + gcc_checking_assert (TREE_VISITED (t)); + return *tree_map.get (t); +} + +/* Insert T into the map, return its tag number. */ + +int +trees_out::insert (tree t, walk_kind walk) +{ + gcc_checking_assert (walk != WK_normal || !TREE_VISITED (t)); + int tag = --ref_num; + bool existed; + int &slot = tree_map.get_or_insert (t, &existed); + gcc_checking_assert (TREE_VISITED (t) == existed + && (!existed + || (walk == WK_value && slot == tag_value))); + TREE_VISITED (t) = true; + slot = tag; + + return tag; +} + +/* Insert T into the backreference array. Return its back reference + number. */ + +int +trees_in::insert (tree t) +{ + gcc_checking_assert (t || get_overrun ()); + back_refs.safe_push (t); + return -(int)back_refs.length (); +} + +/* A chained set of decls. */ + +void +trees_out::chained_decls (tree decls) +{ + for (; decls; decls = DECL_CHAIN (decls)) + { + if (VAR_OR_FUNCTION_DECL_P (decls) + && DECL_LOCAL_DECL_P (decls)) + { + /* Make sure this is the first encounter, and mark for + walk-by-value. */ + gcc_checking_assert (!TREE_VISITED (decls) + && !DECL_TEMPLATE_INFO (decls)); + mark_by_value (decls); + } + tree_node (decls); + } + tree_node (NULL_TREE); +} + +tree +trees_in::chained_decls () +{ + tree decls = NULL_TREE; + for (tree *chain = &decls;;) + if (tree decl = tree_node ()) + { + if (!DECL_P (decl) || DECL_CHAIN (decl)) + { + set_overrun (); + break; + } + *chain = decl; + chain = &DECL_CHAIN (decl); + } + else + break; + + return decls; +} + +/* A vector of decls following DECL_CHAIN. */ + +void +trees_out::vec_chained_decls (tree decls) +{ + if (streaming_p ()) + { + unsigned len = 0; + + for (tree decl = decls; decl; decl = DECL_CHAIN (decl)) + len++; + u (len); + } + + for (tree decl = decls; decl; decl = DECL_CHAIN (decl)) + { + if (DECL_IMPLICIT_TYPEDEF_P (decl) + && TYPE_NAME (TREE_TYPE (decl)) != decl) + /* An anonynmous struct with a typedef name. An odd thing to + write. */ + tree_node (NULL_TREE); + else + tree_node (decl); + } +} + +vec<tree, va_heap> * +trees_in::vec_chained_decls () +{ + vec<tree, va_heap> *v = NULL; + + if (unsigned len = u ()) + { + vec_alloc (v, len); + + for (unsigned ix = 0; ix < len; ix++) + { + tree decl = tree_node (); + if (decl && !DECL_P (decl)) + { + set_overrun (); + break; + } + v->quick_push (decl); + } + + if (get_overrun ()) + { + vec_free (v); + v = NULL; + } + } + + return v; +} + +/* A vector of trees. */ + +void +trees_out::tree_vec (vec<tree, va_gc> *v) +{ + unsigned len = vec_safe_length (v); + if (streaming_p ()) + u (len); + for (unsigned ix = 0; ix != len; ix++) + tree_node ((*v)[ix]); +} + +vec<tree, va_gc> * +trees_in::tree_vec () +{ + vec<tree, va_gc> *v = NULL; + if (unsigned len = u ()) + { + vec_alloc (v, len); + for (unsigned ix = 0; ix != len; ix++) + v->quick_push (tree_node ()); + } + return v; +} + +/* A vector of tree pairs. */ + +void +trees_out::tree_pair_vec (vec<tree_pair_s, va_gc> *v) +{ + unsigned len = vec_safe_length (v); + if (streaming_p ()) + u (len); + if (len) + for (unsigned ix = 0; ix != len; ix++) + { + tree_pair_s const &s = (*v)[ix]; + tree_node (s.purpose); + tree_node (s.value); + } +} + +vec<tree_pair_s, va_gc> * +trees_in::tree_pair_vec () +{ + vec<tree_pair_s, va_gc> *v = NULL; + if (unsigned len = u ()) + { + vec_alloc (v, len); + for (unsigned ix = 0; ix != len; ix++) + { + tree_pair_s s; + s.purpose = tree_node (); + s.value = tree_node (); + v->quick_push (s); + } + } + return v; +} + +void +trees_out::tree_list (tree list, bool has_purpose) +{ + for (; list; list = TREE_CHAIN (list)) + { + gcc_checking_assert (TREE_VALUE (list)); + tree_node (TREE_VALUE (list)); + if (has_purpose) + tree_node (TREE_PURPOSE (list)); + } + tree_node (NULL_TREE); +} + +tree +trees_in::tree_list (bool has_purpose) +{ + tree res = NULL_TREE; + + for (tree *chain = &res; tree value = tree_node (); + chain = &TREE_CHAIN (*chain)) + { + tree purpose = has_purpose ? tree_node () : NULL_TREE; + *chain = build_tree_list (purpose, value); + } + + return res; +} +/* Start tree write. Write information to allocate the receiving + node. */ + +void +trees_out::start (tree t, bool code_streamed) +{ + if (TYPE_P (t)) + { + enum tree_code code = TREE_CODE (t); + gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t); + /* All these types are TYPE_NON_COMMON. */ + gcc_checking_assert (code == RECORD_TYPE + || code == UNION_TYPE + || code == ENUMERAL_TYPE + || code == TEMPLATE_TYPE_PARM + || code == TEMPLATE_TEMPLATE_PARM + || code == BOUND_TEMPLATE_TEMPLATE_PARM); + } + + if (!code_streamed) + u (TREE_CODE (t)); + + switch (TREE_CODE (t)) + { + default: + if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_vl_exp) + u (VL_EXP_OPERAND_LENGTH (t)); + break; + + case INTEGER_CST: + u (TREE_INT_CST_NUNITS (t)); + u (TREE_INT_CST_EXT_NUNITS (t)); + u (TREE_INT_CST_OFFSET_NUNITS (t)); + break; + + case OMP_CLAUSE: + state->extensions |= SE_OPENMP; + u (OMP_CLAUSE_CODE (t)); + break; + + case STRING_CST: + str (TREE_STRING_POINTER (t), TREE_STRING_LENGTH (t)); + break; + + case VECTOR_CST: + u (VECTOR_CST_LOG2_NPATTERNS (t)); + u (VECTOR_CST_NELTS_PER_PATTERN (t)); + break; + + case TREE_BINFO: + u (BINFO_N_BASE_BINFOS (t)); + break; + + case TREE_VEC: + u (TREE_VEC_LENGTH (t)); + break; + + case FIXED_CST: + case POLY_INT_CST: + gcc_unreachable (); /* Not supported in C++. */ + break; + + case IDENTIFIER_NODE: + case SSA_NAME: + case TARGET_MEM_REF: + case TRANSLATION_UNIT_DECL: + /* We shouldn't meet these. */ + gcc_unreachable (); + break; + } +} + +/* Start tree read. Allocate the receiving node. */ + +tree +trees_in::start (unsigned code) +{ + tree t = NULL_TREE; + + if (!code) + code = u (); + + switch (code) + { + default: + if (code >= MAX_TREE_CODES) + { + fail: + set_overrun (); + return NULL_TREE; + } + else if (TREE_CODE_CLASS (code) == tcc_vl_exp) + { + unsigned ops = u (); + t = build_vl_exp (tree_code (code), ops); + } + else + t = make_node (tree_code (code)); + break; + + case INTEGER_CST: + { + unsigned n = u (); + unsigned e = u (); + t = make_int_cst (n, e); + TREE_INT_CST_OFFSET_NUNITS(t) = u (); + } + break; + + case OMP_CLAUSE: + { + if (!(state->extensions & SE_OPENMP)) + goto fail; + + unsigned omp_code = u (); + t = build_omp_clause (UNKNOWN_LOCATION, omp_clause_code (omp_code)); + } + break; + + case STRING_CST: + { + size_t l; + const char *chars = str (&l); + t = build_string (l, chars); + } + break; + + case VECTOR_CST: + { + unsigned log2_npats = u (); + unsigned elts_per = u (); + t = make_vector (log2_npats, elts_per); + } + break; + + case TREE_BINFO: + t = make_tree_binfo (u ()); + break; + + case TREE_VEC: + t = make_tree_vec (u ()); + break; + + case FIXED_CST: + case IDENTIFIER_NODE: + case POLY_INT_CST: + case SSA_NAME: + case TARGET_MEM_REF: + case TRANSLATION_UNIT_DECL: + goto fail; + } + + return t; +} + +/* The structure streamers access the raw fields, because the + alternative, of using the accessor macros can require using + different accessors for the same underlying field, depending on the + tree code. That's both confusing and annoying. */ + +/* Read & write the core boolean flags. */ + +void +trees_out::core_bools (tree t) +{ +#define WB(X) (b (X)) + tree_code code = TREE_CODE (t); + + WB (t->base.side_effects_flag); + WB (t->base.constant_flag); + WB (t->base.addressable_flag); + WB (t->base.volatile_flag); + WB (t->base.readonly_flag); + /* base.asm_written_flag is a property of the current TU's use of + this decl. */ + WB (t->base.nowarning_flag); + /* base.visited read as zero (it's set for writer, because that's + how we mark nodes). */ + /* base.used_flag is not streamed. Readers may set TREE_USED of + decls they use. */ + WB (t->base.nothrow_flag); + WB (t->base.static_flag); + if (TREE_CODE_CLASS (code) != tcc_type) + /* This is TYPE_CACHED_VALUES_P for types. */ + WB (t->base.public_flag); + WB (t->base.private_flag); + WB (t->base.protected_flag); + WB (t->base.deprecated_flag); + WB (t->base.default_def_flag); + + switch (code) + { + case CALL_EXPR: + case INTEGER_CST: + case SSA_NAME: + case TARGET_MEM_REF: + case TREE_VEC: + /* These use different base.u fields. */ + break; + + default: + WB (t->base.u.bits.lang_flag_0); + bool flag_1 = t->base.u.bits.lang_flag_1; + if (!flag_1) + ; + else if (code == TEMPLATE_INFO) + /* This is TI_PENDING_TEMPLATE_FLAG, not relevant to reader. */ + flag_1 = false; + else if (code == VAR_DECL) + { + /* This is DECL_INITIALIZED_P. */ + if (DECL_CONTEXT (t) + && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL) + /* We'll set this when reading the definition. */ + flag_1 = false; + } + WB (flag_1); + WB (t->base.u.bits.lang_flag_2); + WB (t->base.u.bits.lang_flag_3); + WB (t->base.u.bits.lang_flag_4); + WB (t->base.u.bits.lang_flag_5); + WB (t->base.u.bits.lang_flag_6); + WB (t->base.u.bits.saturating_flag); + WB (t->base.u.bits.unsigned_flag); + WB (t->base.u.bits.packed_flag); + WB (t->base.u.bits.user_align); + WB (t->base.u.bits.nameless_flag); + WB (t->base.u.bits.atomic_flag); + break; + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) + { + WB (t->type_common.no_force_blk_flag); + WB (t->type_common.needs_constructing_flag); + WB (t->type_common.transparent_aggr_flag); + WB (t->type_common.restrict_flag); + WB (t->type_common.string_flag); + WB (t->type_common.lang_flag_0); + WB (t->type_common.lang_flag_1); + WB (t->type_common.lang_flag_2); + WB (t->type_common.lang_flag_3); + WB (t->type_common.lang_flag_4); + WB (t->type_common.lang_flag_5); + WB (t->type_common.lang_flag_6); + WB (t->type_common.typeless_storage); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + { + WB (t->decl_common.nonlocal_flag); + WB (t->decl_common.virtual_flag); + WB (t->decl_common.ignored_flag); + WB (t->decl_common.abstract_flag); + WB (t->decl_common.artificial_flag); + WB (t->decl_common.preserve_flag); + WB (t->decl_common.debug_expr_is_from); + WB (t->decl_common.lang_flag_0); + WB (t->decl_common.lang_flag_1); + WB (t->decl_common.lang_flag_2); + WB (t->decl_common.lang_flag_3); + WB (t->decl_common.lang_flag_4); + WB (t->decl_common.lang_flag_5); + WB (t->decl_common.lang_flag_6); + WB (t->decl_common.lang_flag_7); + WB (t->decl_common.lang_flag_8); + WB (t->decl_common.decl_flag_0); + + { + /* DECL_EXTERNAL -> decl_flag_1 + == it is defined elsewhere + DECL_NOT_REALLY_EXTERN -> base.not_really_extern + == that was a lie, it is here */ + + bool is_external = t->decl_common.decl_flag_1; + if (!is_external) + /* decl_flag_1 is DECL_EXTERNAL. Things we emit here, might + well be external from the POV of an importer. */ + // FIXME: Do we need to know if this is a TEMPLATE_RESULT -- + // a flag from the caller? + switch (code) + { + default: + break; + + case VAR_DECL: + if (TREE_PUBLIC (t) + && !DECL_VAR_DECLARED_INLINE_P (t)) + is_external = true; + break; + + case FUNCTION_DECL: + if (TREE_PUBLIC (t) + && !DECL_DECLARED_INLINE_P (t)) + is_external = true; + break; + } + WB (is_external); + } + + WB (t->decl_common.decl_flag_2); + WB (t->decl_common.decl_flag_3); + WB (t->decl_common.not_gimple_reg_flag); + WB (t->decl_common.decl_by_reference_flag); + WB (t->decl_common.decl_read_flag); + WB (t->decl_common.decl_nonshareable_flag); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + WB (t->decl_with_vis.defer_output); + WB (t->decl_with_vis.hard_register); + WB (t->decl_with_vis.common_flag); + WB (t->decl_with_vis.in_text_section); + WB (t->decl_with_vis.in_constant_pool); + WB (t->decl_with_vis.dllimport_flag); + WB (t->decl_with_vis.weak_flag); + WB (t->decl_with_vis.seen_in_bind_expr); + WB (t->decl_with_vis.comdat_flag); + WB (t->decl_with_vis.visibility_specified); + WB (t->decl_with_vis.init_priority_p); + WB (t->decl_with_vis.shadowed_for_var_p); + WB (t->decl_with_vis.cxx_constructor); + WB (t->decl_with_vis.cxx_destructor); + WB (t->decl_with_vis.final); + WB (t->decl_with_vis.regdecl_flag); + } + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + { + WB (t->function_decl.static_ctor_flag); + WB (t->function_decl.static_dtor_flag); + WB (t->function_decl.uninlinable); + WB (t->function_decl.possibly_inlined); + WB (t->function_decl.novops_flag); + WB (t->function_decl.returns_twice_flag); + WB (t->function_decl.malloc_flag); + WB (t->function_decl.declared_inline_flag); + WB (t->function_decl.no_inline_warning_flag); + WB (t->function_decl.no_instrument_function_entry_exit); + WB (t->function_decl.no_limit_stack); + WB (t->function_decl.disregard_inline_limits); + WB (t->function_decl.pure_flag); + WB (t->function_decl.looping_const_or_pure_flag); + + WB (t->function_decl.has_debug_args_flag); + WB (t->function_decl.versioned_function); + + /* decl_type is a (misnamed) 2 bit discriminator. */ + unsigned kind = t->function_decl.decl_type; + WB ((kind >> 0) & 1); + WB ((kind >> 1) & 1); + } +#undef WB +} + +bool +trees_in::core_bools (tree t) +{ +#define RB(X) ((X) = b ()) + tree_code code = TREE_CODE (t); + + RB (t->base.side_effects_flag); + RB (t->base.constant_flag); + RB (t->base.addressable_flag); + RB (t->base.volatile_flag); + RB (t->base.readonly_flag); + /* base.asm_written_flag is not streamed. */ + RB (t->base.nowarning_flag); + /* base.visited is not streamed. */ + /* base.used_flag is not streamed. */ + RB (t->base.nothrow_flag); + RB (t->base.static_flag); + if (TREE_CODE_CLASS (code) != tcc_type) + RB (t->base.public_flag); + RB (t->base.private_flag); + RB (t->base.protected_flag); + RB (t->base.deprecated_flag); + RB (t->base.default_def_flag); + + switch (code) + { + case CALL_EXPR: + case INTEGER_CST: + case SSA_NAME: + case TARGET_MEM_REF: + case TREE_VEC: + /* These use different base.u fields. */ + break; + + default: + RB (t->base.u.bits.lang_flag_0); + RB (t->base.u.bits.lang_flag_1); + RB (t->base.u.bits.lang_flag_2); + RB (t->base.u.bits.lang_flag_3); + RB (t->base.u.bits.lang_flag_4); + RB (t->base.u.bits.lang_flag_5); + RB (t->base.u.bits.lang_flag_6); + RB (t->base.u.bits.saturating_flag); + RB (t->base.u.bits.unsigned_flag); + RB (t->base.u.bits.packed_flag); + RB (t->base.u.bits.user_align); + RB (t->base.u.bits.nameless_flag); + RB (t->base.u.bits.atomic_flag); + break; + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) + { + RB (t->type_common.no_force_blk_flag); + RB (t->type_common.needs_constructing_flag); + RB (t->type_common.transparent_aggr_flag); + RB (t->type_common.restrict_flag); + RB (t->type_common.string_flag); + RB (t->type_common.lang_flag_0); + RB (t->type_common.lang_flag_1); + RB (t->type_common.lang_flag_2); + RB (t->type_common.lang_flag_3); + RB (t->type_common.lang_flag_4); + RB (t->type_common.lang_flag_5); + RB (t->type_common.lang_flag_6); + RB (t->type_common.typeless_storage); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + { + RB (t->decl_common.nonlocal_flag); + RB (t->decl_common.virtual_flag); + RB (t->decl_common.ignored_flag); + RB (t->decl_common.abstract_flag); + RB (t->decl_common.artificial_flag); + RB (t->decl_common.preserve_flag); + RB (t->decl_common.debug_expr_is_from); + RB (t->decl_common.lang_flag_0); + RB (t->decl_common.lang_flag_1); + RB (t->decl_common.lang_flag_2); + RB (t->decl_common.lang_flag_3); + RB (t->decl_common.lang_flag_4); + RB (t->decl_common.lang_flag_5); + RB (t->decl_common.lang_flag_6); + RB (t->decl_common.lang_flag_7); + RB (t->decl_common.lang_flag_8); + RB (t->decl_common.decl_flag_0); + RB (t->decl_common.decl_flag_1); + RB (t->decl_common.decl_flag_2); + RB (t->decl_common.decl_flag_3); + RB (t->decl_common.not_gimple_reg_flag); + RB (t->decl_common.decl_by_reference_flag); + RB (t->decl_common.decl_read_flag); + RB (t->decl_common.decl_nonshareable_flag); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + RB (t->decl_with_vis.defer_output); + RB (t->decl_with_vis.hard_register); + RB (t->decl_with_vis.common_flag); + RB (t->decl_with_vis.in_text_section); + RB (t->decl_with_vis.in_constant_pool); + RB (t->decl_with_vis.dllimport_flag); + RB (t->decl_with_vis.weak_flag); + RB (t->decl_with_vis.seen_in_bind_expr); + RB (t->decl_with_vis.comdat_flag); + RB (t->decl_with_vis.visibility_specified); + RB (t->decl_with_vis.init_priority_p); + RB (t->decl_with_vis.shadowed_for_var_p); + RB (t->decl_with_vis.cxx_constructor); + RB (t->decl_with_vis.cxx_destructor); + RB (t->decl_with_vis.final); + RB (t->decl_with_vis.regdecl_flag); + } + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + { + RB (t->function_decl.static_ctor_flag); + RB (t->function_decl.static_dtor_flag); + RB (t->function_decl.uninlinable); + RB (t->function_decl.possibly_inlined); + RB (t->function_decl.novops_flag); + RB (t->function_decl.returns_twice_flag); + RB (t->function_decl.malloc_flag); + RB (t->function_decl.declared_inline_flag); + RB (t->function_decl.no_inline_warning_flag); + RB (t->function_decl.no_instrument_function_entry_exit); + RB (t->function_decl.no_limit_stack); + RB (t->function_decl.disregard_inline_limits); + RB (t->function_decl.pure_flag); + RB (t->function_decl.looping_const_or_pure_flag); + + RB (t->function_decl.has_debug_args_flag); + RB (t->function_decl.versioned_function); + + /* decl_type is a (misnamed) 2 bit discriminator. */ + unsigned kind = 0; + kind |= unsigned (b ()) << 0; + kind |= unsigned (b ()) << 1; + t->function_decl.decl_type = function_decl_type (kind); + } +#undef RB + return !get_overrun (); +} + +void +trees_out::lang_decl_bools (tree t) +{ +#define WB(X) (b (X)) + const struct lang_decl *lang = DECL_LANG_SPECIFIC (t); + + WB (lang->u.base.language == lang_cplusplus); + WB ((lang->u.base.use_template >> 0) & 1); + WB ((lang->u.base.use_template >> 1) & 1); + /* Do not write lang->u.base.not_really_extern, importer will set + when reading the definition (if any). */ + WB (lang->u.base.initialized_in_class); + WB (lang->u.base.threadprivate_or_deleted_p); + /* Do not write lang->u.base.anticipated_p, it is a property of the + current TU. */ + WB (lang->u.base.friend_or_tls); + WB (lang->u.base.unknown_bound_p); + /* Do not write lang->u.base.odr_used, importer will recalculate if + they do ODR use this decl. */ + WB (lang->u.base.concept_p); + WB (lang->u.base.var_declared_inline_p); + WB (lang->u.base.dependent_init_p); + WB (lang->u.base.module_purview_p); + if (VAR_OR_FUNCTION_DECL_P (t)) + WB (lang->u.base.module_pending_p); + switch (lang->u.base.selector) + { + default: + gcc_unreachable (); + + case lds_fn: /* lang_decl_fn. */ + WB (lang->u.fn.global_ctor_p); + WB (lang->u.fn.global_dtor_p); + WB (lang->u.fn.static_function); + WB (lang->u.fn.pure_virtual); + WB (lang->u.fn.defaulted_p); + WB (lang->u.fn.has_in_charge_parm_p); + WB (lang->u.fn.has_vtt_parm_p); + /* There shouldn't be a pending inline at this point. */ + gcc_assert (!lang->u.fn.pending_inline_p); + WB (lang->u.fn.nonconverting); + WB (lang->u.fn.thunk_p); + WB (lang->u.fn.this_thunk_p); + /* Do not stream lang->u.hidden_friend_p, it is a property of + the TU. */ + WB (lang->u.fn.omp_declare_reduction_p); + WB (lang->u.fn.has_dependent_explicit_spec_p); + WB (lang->u.fn.immediate_fn_p); + WB (lang->u.fn.maybe_deleted); + goto lds_min; + + case lds_decomp: /* lang_decl_decomp. */ + /* No bools. */ + goto lds_min; + + case lds_min: /* lang_decl_min. */ + lds_min: + /* No bools. */ + break; + + case lds_ns: /* lang_decl_ns. */ + /* No bools. */ + break; + + case lds_parm: /* lang_decl_parm. */ + /* No bools. */ + break; + } +#undef WB +} + +bool +trees_in::lang_decl_bools (tree t) +{ +#define RB(X) ((X) = b ()) + struct lang_decl *lang = DECL_LANG_SPECIFIC (t); + + lang->u.base.language = b () ? lang_cplusplus : lang_c; + unsigned v; + v = b () << 0; + v |= b () << 1; + lang->u.base.use_template = v; + /* lang->u.base.not_really_extern is not streamed. */ + RB (lang->u.base.initialized_in_class); + RB (lang->u.base.threadprivate_or_deleted_p); + /* lang->u.base.anticipated_p is not streamed. */ + RB (lang->u.base.friend_or_tls); + RB (lang->u.base.unknown_bound_p); + /* lang->u.base.odr_used is not streamed. */ + RB (lang->u.base.concept_p); + RB (lang->u.base.var_declared_inline_p); + RB (lang->u.base.dependent_init_p); + RB (lang->u.base.module_purview_p); + if (VAR_OR_FUNCTION_DECL_P (t)) + RB (lang->u.base.module_pending_p); + switch (lang->u.base.selector) + { + default: + gcc_unreachable (); + + case lds_fn: /* lang_decl_fn. */ + RB (lang->u.fn.global_ctor_p); + RB (lang->u.fn.global_dtor_p); + RB (lang->u.fn.static_function); + RB (lang->u.fn.pure_virtual); + RB (lang->u.fn.defaulted_p); + RB (lang->u.fn.has_in_charge_parm_p); + RB (lang->u.fn.has_vtt_parm_p); + RB (lang->u.fn.nonconverting); + RB (lang->u.fn.thunk_p); + RB (lang->u.fn.this_thunk_p); + /* lang->u.fn.hidden_friend_p is not streamed. */ + RB (lang->u.fn.omp_declare_reduction_p); + RB (lang->u.fn.has_dependent_explicit_spec_p); + RB (lang->u.fn.immediate_fn_p); + RB (lang->u.fn.maybe_deleted); + goto lds_min; + + case lds_decomp: /* lang_decl_decomp. */ + /* No bools. */ + goto lds_min; + + case lds_min: /* lang_decl_min. */ + lds_min: + /* No bools. */ + break; + + case lds_ns: /* lang_decl_ns. */ + /* No bools. */ + break; + + case lds_parm: /* lang_decl_parm. */ + /* No bools. */ + break; + } +#undef RB + return !get_overrun (); +} + +void +trees_out::lang_type_bools (tree t) +{ +#define WB(X) (b (X)) + const struct lang_type *lang = TYPE_LANG_SPECIFIC (t); + + WB (lang->has_type_conversion); + WB (lang->has_copy_ctor); + WB (lang->has_default_ctor); + WB (lang->const_needs_init); + WB (lang->ref_needs_init); + WB (lang->has_const_copy_assign); + WB ((lang->use_template >> 0) & 1); + WB ((lang->use_template >> 1) & 1); + + WB (lang->has_mutable); + WB (lang->com_interface); + WB (lang->non_pod_class); + WB (lang->nearly_empty_p); + WB (lang->user_align); + WB (lang->has_copy_assign); + WB (lang->has_new); + WB (lang->has_array_new); + + WB ((lang->gets_delete >> 0) & 1); + WB ((lang->gets_delete >> 1) & 1); + // Interfaceness is recalculated upon reading. May have to revisit? + // How do dllexport and dllimport interact across a module? + // lang->interface_only + // lang->interface_unknown + WB (lang->contains_empty_class_p); + WB (lang->anon_aggr); + WB (lang->non_zero_init); + WB (lang->empty_p); + + WB (lang->vec_new_uses_cookie); + WB (lang->declared_class); + WB (lang->diamond_shaped); + WB (lang->repeated_base); + gcc_assert (!lang->being_defined); + // lang->debug_requested + WB (lang->fields_readonly); + WB (lang->ptrmemfunc_flag); + + WB (lang->lazy_default_ctor); + WB (lang->lazy_copy_ctor); + WB (lang->lazy_copy_assign); + WB (lang->lazy_destructor); + WB (lang->has_const_copy_ctor); + WB (lang->has_complex_copy_ctor); + WB (lang->has_complex_copy_assign); + WB (lang->non_aggregate); + + WB (lang->has_complex_dflt); + WB (lang->has_list_ctor); + WB (lang->non_std_layout); + WB (lang->is_literal); + WB (lang->lazy_move_ctor); + WB (lang->lazy_move_assign); + WB (lang->has_complex_move_ctor); + WB (lang->has_complex_move_assign); + + WB (lang->has_constexpr_ctor); + WB (lang->unique_obj_representations); + WB (lang->unique_obj_representations_set); +#undef WB +} + +bool +trees_in::lang_type_bools (tree t) +{ +#define RB(X) ((X) = b ()) + struct lang_type *lang = TYPE_LANG_SPECIFIC (t); + + RB (lang->has_type_conversion); + RB (lang->has_copy_ctor); + RB (lang->has_default_ctor); + RB (lang->const_needs_init); + RB (lang->ref_needs_init); + RB (lang->has_const_copy_assign); + unsigned v; + v = b () << 0; + v |= b () << 1; + lang->use_template = v; + + RB (lang->has_mutable); + RB (lang->com_interface); + RB (lang->non_pod_class); + RB (lang->nearly_empty_p); + RB (lang->user_align); + RB (lang->has_copy_assign); + RB (lang->has_new); + RB (lang->has_array_new); + + v = b () << 0; + v |= b () << 1; + lang->gets_delete = v; + // lang->interface_only + // lang->interface_unknown + lang->interface_unknown = true; // Redetermine interface + RB (lang->contains_empty_class_p); + RB (lang->anon_aggr); + RB (lang->non_zero_init); + RB (lang->empty_p); + + RB (lang->vec_new_uses_cookie); + RB (lang->declared_class); + RB (lang->diamond_shaped); + RB (lang->repeated_base); + gcc_assert (!lang->being_defined); + gcc_assert (!lang->debug_requested); + RB (lang->fields_readonly); + RB (lang->ptrmemfunc_flag); + + RB (lang->lazy_default_ctor); + RB (lang->lazy_copy_ctor); + RB (lang->lazy_copy_assign); + RB (lang->lazy_destructor); + RB (lang->has_const_copy_ctor); + RB (lang->has_complex_copy_ctor); + RB (lang->has_complex_copy_assign); + RB (lang->non_aggregate); + + RB (lang->has_complex_dflt); + RB (lang->has_list_ctor); + RB (lang->non_std_layout); + RB (lang->is_literal); + RB (lang->lazy_move_ctor); + RB (lang->lazy_move_assign); + RB (lang->has_complex_move_ctor); + RB (lang->has_complex_move_assign); + + RB (lang->has_constexpr_ctor); + RB (lang->unique_obj_representations); + RB (lang->unique_obj_representations_set); +#undef RB + return !get_overrun (); +} + +/* Read & write the core values and pointers. */ + +void +trees_out::core_vals (tree t) +{ +#define WU(X) (u (X)) +#define WT(X) (tree_node (X)) + tree_code code = TREE_CODE (t); + + /* First by shape of the tree. */ + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) + { + /* Write this early, for better log information. */ + WT (t->decl_minimal.name); + if (!DECL_TEMPLATE_PARM_P (t)) + WT (t->decl_minimal.context); + + if (state) + state->write_location (*this, t->decl_minimal.locus); + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) + { + /* The only types we write also have TYPE_NON_COMMON. */ + gcc_checking_assert (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON)); + + /* We only stream the main variant. */ + gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t); + + /* Stream the name & context first, for better log information */ + WT (t->type_common.name); + WT (t->type_common.context); + + /* By construction we want to make sure we have the canonical + and main variants already in the type table, so emit them + now. */ + WT (t->type_common.main_variant); + + tree canonical = t->type_common.canonical; + if (canonical && DECL_TEMPLATE_PARM_P (TYPE_NAME (t))) + /* We do not want to wander into different templates. + Reconstructed on stream in. */ + canonical = t; + WT (canonical); + + /* type_common.next_variant is internally manipulated. */ + /* type_common.pointer_to, type_common.reference_to. */ + + if (streaming_p ()) + { + WU (t->type_common.precision); + WU (t->type_common.contains_placeholder_bits); + WU (t->type_common.mode); + WU (t->type_common.align); + } + + if (!RECORD_OR_UNION_CODE_P (code)) + { + WT (t->type_common.size); + WT (t->type_common.size_unit); + } + WT (t->type_common.attributes); + + WT (t->type_common.common.chain); /* TYPE_STUB_DECL. */ + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + { + if (streaming_p ()) + { + WU (t->decl_common.mode); + WU (t->decl_common.off_align); + WU (t->decl_common.align); + } + + /* For templates these hold instantiation (partial and/or + specialization) information. */ + if (code != TEMPLATE_DECL) + { + WT (t->decl_common.size); + WT (t->decl_common.size_unit); + } + + WT (t->decl_common.attributes); + // FIXME: Does this introduce cross-decl links? For instance + // from instantiation to the template. If so, we'll need more + // deduplication logic. I think we'll need to walk the blocks + // of the owning function_decl's abstract origin in tandem, to + // generate the locating data needed? + WT (t->decl_common.abstract_origin); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + WT (t->decl_with_vis.assembler_name); + if (streaming_p ()) + WU (t->decl_with_vis.visibility); + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON)) + { + /* Records and unions hold FIELDS, VFIELD & BINFO on these + things. */ + if (!RECORD_OR_UNION_CODE_P (code) && code != ENUMERAL_TYPE) + { + // FIXME: These are from tpl_parm_value's 'type' writing. + // Perhaps it should just be doing them directly? + gcc_checking_assert (code == TEMPLATE_TYPE_PARM + || code == TEMPLATE_TEMPLATE_PARM + || code == BOUND_TEMPLATE_TEMPLATE_PARM); + gcc_checking_assert (!TYPE_CACHED_VALUES_P (t)); + WT (t->type_non_common.values); + WT (t->type_non_common.maxval); + WT (t->type_non_common.minval); + } + + WT (t->type_non_common.lang_1); + } + + if (CODE_CONTAINS_STRUCT (code, TS_EXP)) + { + if (state) + state->write_location (*this, t->exp.locus); + + /* Walk in forward order, as (for instance) REQUIRES_EXPR has a + bunch of unscoped parms on its first operand. It's safer to + create those in order. */ + bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp; + for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) + : TREE_OPERAND_LENGTH (t)), + ix = unsigned (vl); ix != limit; ix++) + WT (TREE_OPERAND (t, ix)); + } + else + /* The CODE_CONTAINS tables were inaccurate when I started. */ + gcc_checking_assert (TREE_CODE_CLASS (code) != tcc_expression + && TREE_CODE_CLASS (code) != tcc_binary + && TREE_CODE_CLASS (code) != tcc_unary + && TREE_CODE_CLASS (code) != tcc_reference + && TREE_CODE_CLASS (code) != tcc_comparison + && TREE_CODE_CLASS (code) != tcc_statement + && TREE_CODE_CLASS (code) != tcc_vl_exp); + + /* Then by CODE. Special cases and/or 1:1 tree shape + correspondance. */ + switch (code) + { + default: + break; + + case ARGUMENT_PACK_SELECT: /* Transient during instantiation. */ + case DEFERRED_PARSE: /* Expanded upon completion of + outermost class. */ + case IDENTIFIER_NODE: /* Streamed specially. */ + case BINDING_VECTOR: /* Only in namespace-scope symbol + table. */ + case SSA_NAME: + case TRANSLATION_UNIT_DECL: /* There is only one, it is a + global_tree. */ + case USERDEF_LITERAL: /* Expanded during parsing. */ + gcc_unreachable (); /* Should never meet. */ + + /* Constants. */ + case COMPLEX_CST: + WT (TREE_REALPART (t)); + WT (TREE_IMAGPART (t)); + break; + + case FIXED_CST: + gcc_unreachable (); /* Not supported in C++. */ + + case INTEGER_CST: + if (streaming_p ()) + { + unsigned num = TREE_INT_CST_EXT_NUNITS (t); + for (unsigned ix = 0; ix != num; ix++) + wu (TREE_INT_CST_ELT (t, ix)); + } + break; + + case POLY_INT_CST: + gcc_unreachable (); /* Not supported in C++. */ + + case REAL_CST: + if (streaming_p ()) + buf (TREE_REAL_CST_PTR (t), sizeof (real_value)); + break; + + case STRING_CST: + /* Streamed during start. */ + break; + + case VECTOR_CST: + for (unsigned ix = vector_cst_encoded_nelts (t); ix--;) + WT (VECTOR_CST_ENCODED_ELT (t, ix)); + break; + + /* Decls. */ + case VAR_DECL: + if (DECL_CONTEXT (t) + && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL) + break; + /* FALLTHROUGH */ + + case RESULT_DECL: + case PARM_DECL: + if (DECL_HAS_VALUE_EXPR_P (t)) + WT (DECL_VALUE_EXPR (t)); + /* FALLTHROUGH */ + + case CONST_DECL: + case IMPORTED_DECL: + WT (t->decl_common.initial); + break; + + case FIELD_DECL: + WT (t->field_decl.offset); + WT (t->field_decl.bit_field_type); + WT (t->field_decl.qualifier); /* bitfield unit. */ + WT (t->field_decl.bit_offset); + WT (t->field_decl.fcontext); + WT (t->decl_common.initial); + break; + + case LABEL_DECL: + if (streaming_p ()) + { + WU (t->label_decl.label_decl_uid); + WU (t->label_decl.eh_landing_pad_nr); + } + break; + + case FUNCTION_DECL: + if (streaming_p ()) + { + /* Builtins can be streamed by value when a header declares + them. */ + WU (DECL_BUILT_IN_CLASS (t)); + if (DECL_BUILT_IN_CLASS (t) != NOT_BUILT_IN) + WU (DECL_UNCHECKED_FUNCTION_CODE (t)); + } + + WT (t->function_decl.personality); + WT (t->function_decl.function_specific_target); + WT (t->function_decl.function_specific_optimization); + WT (t->function_decl.vindex); + break; + + case USING_DECL: + /* USING_DECL_DECLS */ + WT (t->decl_common.initial); + /* FALLTHROUGH */ + + case TYPE_DECL: + /* USING_DECL: USING_DECL_SCOPE */ + /* TYPE_DECL: DECL_ORIGINAL_TYPE */ + WT (t->decl_non_common.result); + break; + + /* Miscellaneous common nodes. */ + case BLOCK: + if (state) + { + state->write_location (*this, t->block.locus); + state->write_location (*this, t->block.end_locus); + } + + /* DECL_LOCAL_DECL_P decls are first encountered here and + streamed by value. */ + chained_decls (t->block.vars); + /* nonlocalized_vars is a middle-end thing. */ + WT (t->block.subblocks); + WT (t->block.supercontext); + // FIXME: As for decl's abstract_origin, does this introduce crosslinks? + WT (t->block.abstract_origin); + /* fragment_origin, fragment_chain are middle-end things. */ + WT (t->block.chain); + /* nonlocalized_vars, block_num & die are middle endy/debug + things. */ + break; + + case CALL_EXPR: + if (streaming_p ()) + WU (t->base.u.ifn); + break; + + case CONSTRUCTOR: + { + unsigned len = vec_safe_length (t->constructor.elts); + if (streaming_p ()) + WU (len); + if (len) + for (unsigned ix = 0; ix != len; ix++) + { + const constructor_elt &elt = (*t->constructor.elts)[ix]; + + WT (elt.index); + WT (elt.value); + } + } + break; + + case OMP_CLAUSE: + { + /* The ompcode is serialized in start. */ + if (streaming_p ()) + WU (t->omp_clause.subcode.map_kind); + if (state) + state->write_location (*this, t->omp_clause.locus); + + unsigned len = omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; + for (unsigned ix = 0; ix != len; ix++) + WT (t->omp_clause.ops[ix]); + } + break; + + case STATEMENT_LIST: + for (tree_stmt_iterator iter = tsi_start (t); + !tsi_end_p (iter); tsi_next (&iter)) + if (tree stmt = tsi_stmt (iter)) + WT (stmt); + WT (NULL_TREE); + break; + + case OPTIMIZATION_NODE: + case TARGET_OPTION_NODE: + // FIXME: Our representation for these two nodes is a cache of + // the resulting set of options. Not a record of the options + // that got changed by a particular attribute or pragma. Should + // we record that, or should we record the diff from the command + // line options? The latter seems the right behaviour, but is + // (a) harder, and I guess could introduce strangeness if the + // importer has set some incompatible set of optimization flags? + gcc_unreachable (); + break; + + case TREE_BINFO: + { + WT (t->binfo.common.chain); + WT (t->binfo.offset); + WT (t->binfo.inheritance); + WT (t->binfo.vptr_field); + + WT (t->binfo.vtable); + WT (t->binfo.virtuals); + WT (t->binfo.vtt_subvtt); + WT (t->binfo.vtt_vptr); + + tree_vec (BINFO_BASE_ACCESSES (t)); + unsigned num = vec_safe_length (BINFO_BASE_ACCESSES (t)); + for (unsigned ix = 0; ix != num; ix++) + WT (BINFO_BASE_BINFO (t, ix)); + } + break; + + case TREE_LIST: + WT (t->list.purpose); + WT (t->list.value); + WT (t->list.common.chain); + break; + + case TREE_VEC: + for (unsigned ix = TREE_VEC_LENGTH (t); ix--;) + WT (TREE_VEC_ELT (t, ix)); + /* We stash NON_DEFAULT_TEMPLATE_ARGS_COUNT on TREE_CHAIN! */ + gcc_checking_assert (!t->type_common.common.chain + || (TREE_CODE (t->type_common.common.chain) + == INTEGER_CST)); + WT (t->type_common.common.chain); + break; + + /* C++-specific nodes ... */ + case BASELINK: + WT (((lang_tree_node *)t)->baselink.binfo); + WT (((lang_tree_node *)t)->baselink.functions); + WT (((lang_tree_node *)t)->baselink.access_binfo); + break; + + case CONSTRAINT_INFO: + WT (((lang_tree_node *)t)->constraint_info.template_reqs); + WT (((lang_tree_node *)t)->constraint_info.declarator_reqs); + WT (((lang_tree_node *)t)->constraint_info.associated_constr); + break; + + case DEFERRED_NOEXCEPT: + WT (((lang_tree_node *)t)->deferred_noexcept.pattern); + WT (((lang_tree_node *)t)->deferred_noexcept.args); + break; + + case LAMBDA_EXPR: + WT (((lang_tree_node *)t)->lambda_expression.capture_list); + WT (((lang_tree_node *)t)->lambda_expression.this_capture); + WT (((lang_tree_node *)t)->lambda_expression.extra_scope); + /* pending_proxies is a parse-time thing. */ + gcc_assert (!((lang_tree_node *)t)->lambda_expression.pending_proxies); + if (state) + state->write_location + (*this, ((lang_tree_node *)t)->lambda_expression.locus); + if (streaming_p ()) + { + WU (((lang_tree_node *)t)->lambda_expression.default_capture_mode); + WU (((lang_tree_node *)t)->lambda_expression.discriminator); + } + break; + + case OVERLOAD: + WT (((lang_tree_node *)t)->overload.function); + WT (t->common.chain); + break; + + case PTRMEM_CST: + WT (((lang_tree_node *)t)->ptrmem.member); + break; + + case STATIC_ASSERT: + WT (((lang_tree_node *)t)->static_assertion.condition); + WT (((lang_tree_node *)t)->static_assertion.message); + if (state) + state->write_location + (*this, ((lang_tree_node *)t)->static_assertion.location); + break; + + case TEMPLATE_DECL: + /* Streamed with the template_decl node itself. */ + gcc_checking_assert + (TREE_VISITED (((lang_tree_node *)t)->template_decl.arguments)); + gcc_checking_assert + (TREE_VISITED (((lang_tree_node *)t)->template_decl.result) + || dep_hash->find_dependency (t)->is_alias_tmpl_inst ()); + if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (t)) + WT (DECL_CHAIN (t)); + break; + + case TEMPLATE_INFO: + { + WT (((lang_tree_node *)t)->template_info.tmpl); + WT (((lang_tree_node *)t)->template_info.args); + + const auto *ac = (((lang_tree_node *)t) + ->template_info.deferred_access_checks); + unsigned len = vec_safe_length (ac); + if (streaming_p ()) + u (len); + if (len) + { + for (unsigned ix = 0; ix != len; ix++) + { + const auto &m = (*ac)[ix]; + WT (m.binfo); + WT (m.decl); + WT (m.diag_decl); + if (state) + state->write_location (*this, m.loc); + } + } + } + break; + + case TEMPLATE_PARM_INDEX: + if (streaming_p ()) + { + WU (((lang_tree_node *)t)->tpi.index); + WU (((lang_tree_node *)t)->tpi.level); + WU (((lang_tree_node *)t)->tpi.orig_level); + } + WT (((lang_tree_node *)t)->tpi.decl); + /* TEMPLATE_PARM_DESCENDANTS (AKA TREE_CHAIN) is an internal + cache, do not stream. */ + break; + + case TRAIT_EXPR: + WT (((lang_tree_node *)t)->trait_expression.type1); + WT (((lang_tree_node *)t)->trait_expression.type2); + if (streaming_p ()) + WU (((lang_tree_node *)t)->trait_expression.kind); + break; + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) + { + /* We want to stream the type of a expression-like nodes /after/ + we've streamed the operands. The type often contains (bits + of the) types of the operands, and with things like decltype + and noexcept in play, we really want to stream the decls + defining the type before we try and stream the type on its + own. Otherwise we can find ourselves trying to read in a + decl, when we're already partially reading in a component of + its type. And that's bad. */ + tree type = t->typed.type; + unsigned prec = 0; + + switch (code) + { + default: + break; + + case TEMPLATE_DECL: + /* We fill in the template's type separately. */ + type = NULL_TREE; + break; + + case TYPE_DECL: + if (DECL_ORIGINAL_TYPE (t) && t == TYPE_NAME (type)) + /* This is a typedef. We set its type separately. */ + type = NULL_TREE; + break; + + case ENUMERAL_TYPE: + if (type && !ENUM_FIXED_UNDERLYING_TYPE_P (t)) + { + /* Type is a restricted range integer type derived from the + integer_types. Find the right one. */ + prec = TYPE_PRECISION (type); + tree name = DECL_NAME (TYPE_NAME (type)); + + for (unsigned itk = itk_none; itk--;) + if (integer_types[itk] + && DECL_NAME (TYPE_NAME (integer_types[itk])) == name) + { + type = integer_types[itk]; + break; + } + gcc_assert (type != t->typed.type); + } + break; + } + + WT (type); + if (prec && streaming_p ()) + WU (prec); + } + +#undef WT +#undef WU +} + +// Streaming in a reference to a decl can cause that decl to be +// TREE_USED, which is the mark_used behaviour we need most of the +// time. The trees_in::unused can be incremented to inhibit this, +// which is at least needed for vtables. + +bool +trees_in::core_vals (tree t) +{ +#define RU(X) ((X) = u ()) +#define RUC(T,X) ((X) = T (u ())) +#define RT(X) ((X) = tree_node ()) +#define RTU(X) ((X) = tree_node (true)) + tree_code code = TREE_CODE (t); + + /* First by tree shape. */ + if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) + { + RT (t->decl_minimal.name); + if (!DECL_TEMPLATE_PARM_P (t)) + RT (t->decl_minimal.context); + + /* Don't zap the locus just yet, we don't record it correctly + and thus lose all location information. */ + t->decl_minimal.locus = state->read_location (*this); + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) + { + RT (t->type_common.name); + RT (t->type_common.context); + + RT (t->type_common.main_variant); + RT (t->type_common.canonical); + + /* type_common.next_variant is internally manipulated. */ + /* type_common.pointer_to, type_common.reference_to. */ + + RU (t->type_common.precision); + RU (t->type_common.contains_placeholder_bits); + RUC (machine_mode, t->type_common.mode); + RU (t->type_common.align); + + if (!RECORD_OR_UNION_CODE_P (code)) + { + RT (t->type_common.size); + RT (t->type_common.size_unit); + } + RT (t->type_common.attributes); + + RT (t->type_common.common.chain); /* TYPE_STUB_DECL. */ + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + { + RUC (machine_mode, t->decl_common.mode); + RU (t->decl_common.off_align); + RU (t->decl_common.align); + + if (code != TEMPLATE_DECL) + { + RT (t->decl_common.size); + RT (t->decl_common.size_unit); + } + + RT (t->decl_common.attributes); + RT (t->decl_common.abstract_origin); + } + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + { + RT (t->decl_with_vis.assembler_name); + RUC (symbol_visibility, t->decl_with_vis.visibility); + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON)) + { + /* Records and unions hold FIELDS, VFIELD & BINFO on these + things. */ + if (!RECORD_OR_UNION_CODE_P (code) && code != ENUMERAL_TYPE) + { + /* This is not clobbering TYPE_CACHED_VALUES, because this + is a type that doesn't have any. */ + gcc_checking_assert (!TYPE_CACHED_VALUES_P (t)); + RT (t->type_non_common.values); + RT (t->type_non_common.maxval); + RT (t->type_non_common.minval); + } + + RT (t->type_non_common.lang_1); + } + + if (CODE_CONTAINS_STRUCT (code, TS_EXP)) + { + t->exp.locus = state->read_location (*this); + + bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp; + for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) + : TREE_OPERAND_LENGTH (t)), + ix = unsigned (vl); ix != limit; ix++) + RTU (TREE_OPERAND (t, ix)); + } + + /* Then by CODE. Special cases and/or 1:1 tree shape + correspondance. */ + switch (code) + { + default: + break; + + case ARGUMENT_PACK_SELECT: + case DEFERRED_PARSE: + case IDENTIFIER_NODE: + case BINDING_VECTOR: + case SSA_NAME: + case TRANSLATION_UNIT_DECL: + case USERDEF_LITERAL: + return false; /* Should never meet. */ + + /* Constants. */ + case COMPLEX_CST: + RT (TREE_REALPART (t)); + RT (TREE_IMAGPART (t)); + break; + + case FIXED_CST: + /* Not suported in C++. */ + return false; + + case INTEGER_CST: + { + unsigned num = TREE_INT_CST_EXT_NUNITS (t); + for (unsigned ix = 0; ix != num; ix++) + TREE_INT_CST_ELT (t, ix) = wu (); + } + break; + + case POLY_INT_CST: + /* Not suported in C++. */ + return false; + + case REAL_CST: + if (const void *bytes = buf (sizeof (real_value))) + TREE_REAL_CST_PTR (t) + = reinterpret_cast<real_value *> (memcpy (ggc_alloc<real_value> (), + bytes, sizeof (real_value))); + break; + + case STRING_CST: + /* Streamed during start. */ + break; + + case VECTOR_CST: + for (unsigned ix = vector_cst_encoded_nelts (t); ix--;) + RT (VECTOR_CST_ENCODED_ELT (t, ix)); + break; + + /* Decls. */ + case VAR_DECL: + if (DECL_CONTEXT (t) + && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL) + break; + /* FALLTHROUGH */ + + case RESULT_DECL: + case PARM_DECL: + if (DECL_HAS_VALUE_EXPR_P (t)) + { + /* The DECL_VALUE hash table is a cache, thus if we're + reading a duplicate (which we end up discarding), the + value expr will also be cleaned up at the next gc. */ + tree val = tree_node (); + SET_DECL_VALUE_EXPR (t, val); + } + /* FALLTHROUGH */ + + case CONST_DECL: + case IMPORTED_DECL: + RT (t->decl_common.initial); + break; + + case FIELD_DECL: + RT (t->field_decl.offset); + RT (t->field_decl.bit_field_type); + RT (t->field_decl.qualifier); + RT (t->field_decl.bit_offset); + RT (t->field_decl.fcontext); + RT (t->decl_common.initial); + break; + + case LABEL_DECL: + RU (t->label_decl.label_decl_uid); + RU (t->label_decl.eh_landing_pad_nr); + break; + + case FUNCTION_DECL: + { + unsigned bltin = u (); + t->function_decl.built_in_class = built_in_class (bltin); + if (bltin != NOT_BUILT_IN) + { + bltin = u (); + DECL_UNCHECKED_FUNCTION_CODE (t) = built_in_function (bltin); + } + + RT (t->function_decl.personality); + RT (t->function_decl.function_specific_target); + RT (t->function_decl.function_specific_optimization); + RT (t->function_decl.vindex); + } + break; + + case USING_DECL: + /* USING_DECL_DECLS */ + RT (t->decl_common.initial); + /* FALLTHROUGH */ + + case TYPE_DECL: + /* USING_DECL: USING_DECL_SCOPE */ + /* TYPE_DECL: DECL_ORIGINAL_TYPE */ + RT (t->decl_non_common.result); + break; + + /* Miscellaneous common nodes. */ + case BLOCK: + t->block.locus = state->read_location (*this); + t->block.end_locus = state->read_location (*this); + t->block.vars = chained_decls (); + /* nonlocalized_vars is middle-end. */ + RT (t->block.subblocks); + RT (t->block.supercontext); + RT (t->block.abstract_origin); + /* fragment_origin, fragment_chain are middle-end. */ + RT (t->block.chain); + /* nonlocalized_vars, block_num, die are middle endy/debug + things. */ + break; + + case CALL_EXPR: + RUC (internal_fn, t->base.u.ifn); + break; + + case CONSTRUCTOR: + if (unsigned len = u ()) + { + vec_alloc (t->constructor.elts, len); + for (unsigned ix = 0; ix != len; ix++) + { + constructor_elt elt; + + RT (elt.index); + RTU (elt.value); + t->constructor.elts->quick_push (elt); + } + } + break; + + case OMP_CLAUSE: + { + RU (t->omp_clause.subcode.map_kind); + t->omp_clause.locus = state->read_location (*this); + + unsigned len = omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; + for (unsigned ix = 0; ix != len; ix++) + RT (t->omp_clause.ops[ix]); + } + break; + + case STATEMENT_LIST: + { + tree_stmt_iterator iter = tsi_start (t); + for (tree stmt; RT (stmt);) + tsi_link_after (&iter, stmt, TSI_CONTINUE_LINKING); + } + break; + + case OPTIMIZATION_NODE: + case TARGET_OPTION_NODE: + /* Not yet implemented, see trees_out::core_vals. */ + gcc_unreachable (); + break; + + case TREE_BINFO: + RT (t->binfo.common.chain); + RT (t->binfo.offset); + RT (t->binfo.inheritance); + RT (t->binfo.vptr_field); + + /* Do not mark the vtables as USED in the address expressions + here. */ + unused++; + RT (t->binfo.vtable); + RT (t->binfo.virtuals); + RT (t->binfo.vtt_subvtt); + RT (t->binfo.vtt_vptr); + unused--; + + BINFO_BASE_ACCESSES (t) = tree_vec (); + if (!get_overrun ()) + { + unsigned num = vec_safe_length (BINFO_BASE_ACCESSES (t)); + for (unsigned ix = 0; ix != num; ix++) + BINFO_BASE_APPEND (t, tree_node ()); + } + break; + + case TREE_LIST: + RT (t->list.purpose); + RT (t->list.value); + RT (t->list.common.chain); + break; + + case TREE_VEC: + for (unsigned ix = TREE_VEC_LENGTH (t); ix--;) + RT (TREE_VEC_ELT (t, ix)); + RT (t->type_common.common.chain); + break; + + /* C++-specific nodes ... */ + case BASELINK: + RT (((lang_tree_node *)t)->baselink.binfo); + RTU (((lang_tree_node *)t)->baselink.functions); + RT (((lang_tree_node *)t)->baselink.access_binfo); + break; + + case CONSTRAINT_INFO: + RT (((lang_tree_node *)t)->constraint_info.template_reqs); + RT (((lang_tree_node *)t)->constraint_info.declarator_reqs); + RT (((lang_tree_node *)t)->constraint_info.associated_constr); + break; + + case DEFERRED_NOEXCEPT: + RT (((lang_tree_node *)t)->deferred_noexcept.pattern); + RT (((lang_tree_node *)t)->deferred_noexcept.args); + break; + + case LAMBDA_EXPR: + RT (((lang_tree_node *)t)->lambda_expression.capture_list); + RT (((lang_tree_node *)t)->lambda_expression.this_capture); + RT (((lang_tree_node *)t)->lambda_expression.extra_scope); + /* lambda_expression.pending_proxies is NULL */ + ((lang_tree_node *)t)->lambda_expression.locus + = state->read_location (*this); + RUC (cp_lambda_default_capture_mode_type, + ((lang_tree_node *)t)->lambda_expression.default_capture_mode); + RU (((lang_tree_node *)t)->lambda_expression.discriminator); + break; + + case OVERLOAD: + RT (((lang_tree_node *)t)->overload.function); + RT (t->common.chain); + break; + + case PTRMEM_CST: + RT (((lang_tree_node *)t)->ptrmem.member); + break; + + case STATIC_ASSERT: + RT (((lang_tree_node *)t)->static_assertion.condition); + RT (((lang_tree_node *)t)->static_assertion.message); + ((lang_tree_node *)t)->static_assertion.location + = state->read_location (*this); + break; + + case TEMPLATE_DECL: + /* Streamed when reading the raw template decl itself. */ + gcc_assert (((lang_tree_node *)t)->template_decl.arguments); + gcc_assert (((lang_tree_node *)t)->template_decl.result); + if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (t)) + RT (DECL_CHAIN (t)); + break; + + case TEMPLATE_INFO: + RT (((lang_tree_node *)t)->template_info.tmpl); + RT (((lang_tree_node *)t)->template_info.args); + if (unsigned len = u ()) + { + auto &ac = (((lang_tree_node *)t) + ->template_info.deferred_access_checks); + vec_alloc (ac, len); + for (unsigned ix = 0; ix != len; ix++) + { + deferred_access_check m; + + RT (m.binfo); + RT (m.decl); + RT (m.diag_decl); + m.loc = state->read_location (*this); + ac->quick_push (m); + } + } + break; + + case TEMPLATE_PARM_INDEX: + RU (((lang_tree_node *)t)->tpi.index); + RU (((lang_tree_node *)t)->tpi.level); + RU (((lang_tree_node *)t)->tpi.orig_level); + RT (((lang_tree_node *)t)->tpi.decl); + break; + + case TRAIT_EXPR: + RT (((lang_tree_node *)t)->trait_expression.type1); + RT (((lang_tree_node *)t)->trait_expression.type2); + RUC (cp_trait_kind, ((lang_tree_node *)t)->trait_expression.kind); + break; + } + + if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) + { + tree type = tree_node (); + + if (type && code == ENUMERAL_TYPE && !ENUM_FIXED_UNDERLYING_TYPE_P (t)) + { + unsigned precision = u (); + + type = build_distinct_type_copy (type); + TYPE_PRECISION (type) = precision; + set_min_and_max_values_for_integral_type (type, precision, + TYPE_SIGN (type)); + } + + if (code != TEMPLATE_DECL) + t->typed.type = type; + } + +#undef RT +#undef RM +#undef RU + return !get_overrun (); +} + +void +trees_out::lang_decl_vals (tree t) +{ + const struct lang_decl *lang = DECL_LANG_SPECIFIC (t); +#define WU(X) (u (X)) +#define WT(X) (tree_node (X)) + /* Module index already written. */ + switch (lang->u.base.selector) + { + default: + gcc_unreachable (); + + case lds_fn: /* lang_decl_fn. */ + if (streaming_p ()) + { + if (DECL_NAME (t) && IDENTIFIER_OVL_OP_P (DECL_NAME (t))) + WU (lang->u.fn.ovl_op_code); + } + + if (DECL_CLASS_SCOPE_P (t)) + WT (lang->u.fn.context); + + if (lang->u.fn.thunk_p) + { + /* The thunked-to function. */ + WT (lang->u.fn.befriending_classes); + if (streaming_p ()) + wi (lang->u.fn.u5.fixed_offset); + } + else + WT (lang->u.fn.u5.cloned_function); + + if (FNDECL_USED_AUTO (t)) + WT (lang->u.fn.u.saved_auto_return_type); + + goto lds_min; + + case lds_decomp: /* lang_decl_decomp. */ + WT (lang->u.decomp.base); + goto lds_min; + + case lds_min: /* lang_decl_min. */ + lds_min: + WT (lang->u.min.template_info); + { + tree access = lang->u.min.access; + + /* DECL_ACCESS needs to be maintained by the definition of the + (derived) class that changes the access. The other users + of DECL_ACCESS need to write it here. */ + if (!DECL_THUNK_P (t) + && (DECL_CONTEXT (t) && TYPE_P (DECL_CONTEXT (t)))) + access = NULL_TREE; + + WT (access); + } + break; + + case lds_ns: /* lang_decl_ns. */ + break; + + case lds_parm: /* lang_decl_parm. */ + if (streaming_p ()) + { + WU (lang->u.parm.level); + WU (lang->u.parm.index); + } + break; + } +#undef WU +#undef WT +} + +bool +trees_in::lang_decl_vals (tree t) +{ + struct lang_decl *lang = DECL_LANG_SPECIFIC (t); +#define RU(X) ((X) = u ()) +#define RT(X) ((X) = tree_node ()) + + /* Module index already read. */ + switch (lang->u.base.selector) + { + default: + gcc_unreachable (); + + case lds_fn: /* lang_decl_fn. */ + if (DECL_NAME (t) && IDENTIFIER_OVL_OP_P (DECL_NAME (t))) + { + unsigned code = u (); + + /* Check consistency. */ + if (code >= OVL_OP_MAX + || (ovl_op_info[IDENTIFIER_ASSIGN_OP_P (DECL_NAME (t))][code] + .ovl_op_code) == OVL_OP_ERROR_MARK) + set_overrun (); + else + lang->u.fn.ovl_op_code = code; + } + + if (DECL_CLASS_SCOPE_P (t)) + RT (lang->u.fn.context); + + if (lang->u.fn.thunk_p) + { + RT (lang->u.fn.befriending_classes); + lang->u.fn.u5.fixed_offset = wi (); + } + else + RT (lang->u.fn.u5.cloned_function); + + if (FNDECL_USED_AUTO (t)) + RT (lang->u.fn.u.saved_auto_return_type); + goto lds_min; + + case lds_decomp: /* lang_decl_decomp. */ + RT (lang->u.decomp.base); + goto lds_min; + + case lds_min: /* lang_decl_min. */ + lds_min: + RT (lang->u.min.template_info); + RT (lang->u.min.access); + break; + + case lds_ns: /* lang_decl_ns. */ + break; + + case lds_parm: /* lang_decl_parm. */ + RU (lang->u.parm.level); + RU (lang->u.parm.index); + break; + } +#undef RU +#undef RT + return !get_overrun (); +} + +/* Most of the value contents of lang_type is streamed in + define_class. */ + +void +trees_out::lang_type_vals (tree t) +{ + const struct lang_type *lang = TYPE_LANG_SPECIFIC (t); +#define WU(X) (u (X)) +#define WT(X) (tree_node (X)) + if (streaming_p ()) + WU (lang->align); +#undef WU +#undef WT +} + +bool +trees_in::lang_type_vals (tree t) +{ + struct lang_type *lang = TYPE_LANG_SPECIFIC (t); +#define RU(X) ((X) = u ()) +#define RT(X) ((X) = tree_node ()) + RU (lang->align); +#undef RU +#undef RT + return !get_overrun (); +} + +/* Write out the bools of T, including information about any + LANG_SPECIFIC information. Including allocation of any lang + specific object. */ + +void +trees_out::tree_node_bools (tree t) +{ + gcc_checking_assert (streaming_p ()); + + /* We should never stream a namespace. */ + gcc_checking_assert (TREE_CODE (t) != NAMESPACE_DECL + || DECL_NAMESPACE_ALIAS (t)); + + core_bools (t); + + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_declaration: + { + bool specific = DECL_LANG_SPECIFIC (t) != NULL; + b (specific); + if (specific && VAR_P (t)) + b (DECL_DECOMPOSITION_P (t)); + if (specific) + lang_decl_bools (t); + } + break; + + case tcc_type: + { + bool specific = (TYPE_MAIN_VARIANT (t) == t + && TYPE_LANG_SPECIFIC (t) != NULL); + gcc_assert (TYPE_LANG_SPECIFIC (t) + == TYPE_LANG_SPECIFIC (TYPE_MAIN_VARIANT (t))); + + b (specific); + if (specific) + lang_type_bools (t); + } + break; + + default: + break; + } + + bflush (); +} + +bool +trees_in::tree_node_bools (tree t) +{ + bool ok = core_bools (t); + + if (ok) + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_declaration: + if (b ()) + { + bool decomp = VAR_P (t) && b (); + + ok = maybe_add_lang_decl_raw (t, decomp); + if (ok) + ok = lang_decl_bools (t); + } + break; + + case tcc_type: + if (b ()) + { + ok = maybe_add_lang_type_raw (t); + if (ok) + ok = lang_type_bools (t); + } + break; + + default: + break; + } + + bflush (); + if (!ok || get_overrun ()) + return false; + + return true; +} + + +/* Write out the lang-specifc vals of node T. */ + +void +trees_out::lang_vals (tree t) +{ + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_declaration: + if (DECL_LANG_SPECIFIC (t)) + lang_decl_vals (t); + break; + + case tcc_type: + if (TYPE_MAIN_VARIANT (t) == t && TYPE_LANG_SPECIFIC (t)) + lang_type_vals (t); + break; + + default: + break; + } +} + +bool +trees_in::lang_vals (tree t) +{ + bool ok = true; + + switch (TREE_CODE_CLASS (TREE_CODE (t))) + { + case tcc_declaration: + if (DECL_LANG_SPECIFIC (t)) + ok = lang_decl_vals (t); + break; + + case tcc_type: + if (TYPE_LANG_SPECIFIC (t)) + ok = lang_type_vals (t); + else + TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (TYPE_MAIN_VARIANT (t)); + break; + + default: + break; + } + + return ok; +} + +/* Write out the value fields of node T. */ + +void +trees_out::tree_node_vals (tree t) +{ + core_vals (t); + lang_vals (t); +} + +bool +trees_in::tree_node_vals (tree t) +{ + bool ok = core_vals (t); + if (ok) + ok = lang_vals (t); + + return ok; +} + + +/* If T is a back reference, fixed reference or NULL, write out it's + code and return WK_none. Otherwise return WK_value if we must write + by value, or WK_normal otherwise. */ + +walk_kind +trees_out::ref_node (tree t) +{ + if (!t) + { + if (streaming_p ()) + { + /* NULL_TREE -> tt_null. */ + null_count++; + i (tt_null); + } + return WK_none; + } + + if (!TREE_VISITED (t)) + return WK_normal; + + /* An already-visited tree. It must be in the map. */ + int val = get_tag (t); + + if (val == tag_value) + /* An entry we should walk into. */ + return WK_value; + + const char *kind; + + if (val <= tag_backref) + { + /* Back reference -> -ve number */ + if (streaming_p ()) + i (val); + kind = "backref"; + } + else if (val >= tag_fixed) + { + /* Fixed reference -> tt_fixed */ + val -= tag_fixed; + if (streaming_p ()) + i (tt_fixed), u (val); + kind = "fixed"; + } + + if (streaming_p ()) + { + back_ref_count++; + dump (dumper::TREE) + && dump ("Wrote %s:%d %C:%N%S", kind, val, TREE_CODE (t), t, t); + } + return WK_none; +} + +tree +trees_in::back_ref (int tag) +{ + tree res = NULL_TREE; + + if (tag < 0 && unsigned (~tag) < back_refs.length ()) + res = back_refs[~tag]; + + if (!res + /* Checking TREE_CODE is a dereference, so we know this is not a + wild pointer. Checking the code provides evidence we've not + corrupted something. */ + || TREE_CODE (res) >= MAX_TREE_CODES) + set_overrun (); + else + dump (dumper::TREE) && dump ("Read backref:%d found %C:%N%S", tag, + TREE_CODE (res), res, res); + return res; +} + +unsigned +trees_out::add_indirect_tpl_parms (tree parms) +{ + unsigned len = 0; + for (; parms; parms = TREE_CHAIN (parms), len++) + { + if (TREE_VISITED (parms)) + break; + + int tag = insert (parms); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Indirect:%d template's parameter %u %C:%N", + tag, len, TREE_CODE (parms), parms); + } + + if (streaming_p ()) + u (len); + + return len; +} + +unsigned +trees_in::add_indirect_tpl_parms (tree parms) +{ + unsigned len = u (); + for (unsigned ix = 0; ix != len; parms = TREE_CHAIN (parms), ix++) + { + int tag = insert (parms); + dump (dumper::TREE) + && dump ("Indirect:%d template's parameter %u %C:%N", + tag, ix, TREE_CODE (parms), parms); + } + + return len; +} + +/* We've just found DECL by name. Insert nodes that come with it, but + cannot be found by name, so we'll not accidentally walk into them. */ + +void +trees_out::add_indirects (tree decl) +{ + unsigned count = 0; + + // FIXME:OPTIMIZATION We'll eventually want default fn parms of + // templates and perhaps default template parms too. The former can + // be referenced from instantiations (as they are lazily + // instantiated). Also (deferred?) exception specifications of + // templates. See the note about PARM_DECLs in trees_out::decl_node. + tree inner = decl; + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + count += add_indirect_tpl_parms (DECL_TEMPLATE_PARMS (decl)); + + inner = DECL_TEMPLATE_RESULT (decl); + int tag = insert (inner); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Indirect:%d template's result %C:%N", + tag, TREE_CODE (inner), inner); + count++; + } + + if (TREE_CODE (inner) == TYPE_DECL) + { + /* Make sure the type is in the map too. Otherwise we get + different RECORD_TYPEs for the same type, and things go + south. */ + tree type = TREE_TYPE (inner); + gcc_checking_assert (DECL_ORIGINAL_TYPE (inner) + || TYPE_NAME (type) == inner); + int tag = insert (type); + if (streaming_p ()) + dump (dumper::TREE) && dump ("Indirect:%d decl's type %C:%N", tag, + TREE_CODE (type), type); + count++; + } + + if (streaming_p ()) + { + u (count); + dump (dumper::TREE) && dump ("Inserted %u indirects", count); + } +} + +bool +trees_in::add_indirects (tree decl) +{ + unsigned count = 0; + + tree inner = decl; + if (TREE_CODE (inner) == TEMPLATE_DECL) + { + count += add_indirect_tpl_parms (DECL_TEMPLATE_PARMS (decl)); + + inner = DECL_TEMPLATE_RESULT (decl); + int tag = insert (inner); + dump (dumper::TREE) + && dump ("Indirect:%d templates's result %C:%N", tag, + TREE_CODE (inner), inner); + count++; + } + + if (TREE_CODE (inner) == TYPE_DECL) + { + tree type = TREE_TYPE (inner); + gcc_checking_assert (DECL_ORIGINAL_TYPE (inner) + || TYPE_NAME (type) == inner); + int tag = insert (type); + dump (dumper::TREE) + && dump ("Indirect:%d decl's type %C:%N", tag, TREE_CODE (type), type); + count++; + } + + dump (dumper::TREE) && dump ("Inserted %u indirects", count); + return count == u (); +} + +/* Stream a template parameter. There are 4.5 kinds of parameter: + a) Template - TEMPLATE_DECL->TYPE_DECL->TEMPLATE_TEMPLATE_PARM + TEMPLATE_TYPE_PARM_INDEX TPI + b) Type - TYPE_DECL->TEMPLATE_TYPE_PARM TEMPLATE_TYPE_PARM_INDEX TPI + c.1) NonTYPE - PARM_DECL DECL_INITIAL TPI We meet this first + c.2) NonTYPE - CONST_DECL DECL_INITIAL Same TPI + d) BoundTemplate - TYPE_DECL->BOUND_TEMPLATE_TEMPLATE_PARM + TEMPLATE_TYPE_PARM_INDEX->TPI + TEMPLATE_TEMPLATE_PARM_INFO->TEMPLATE_INFO + + All of these point to a TEMPLATE_PARM_INDEX, and #B also has a TEMPLATE_INFO +*/ + +void +trees_out::tpl_parm_value (tree parm) +{ + gcc_checking_assert (DECL_P (parm) && DECL_TEMPLATE_PARM_P (parm)); + + int parm_tag = insert (parm); + if (streaming_p ()) + { + i (tt_tpl_parm); + dump (dumper::TREE) && dump ("Writing template parm:%d %C:%N", + parm_tag, TREE_CODE (parm), parm); + start (parm); + tree_node_bools (parm); + } + + tree inner = parm; + if (TREE_CODE (inner) == TEMPLATE_DECL) + { + inner = DECL_TEMPLATE_RESULT (inner); + int inner_tag = insert (inner); + if (streaming_p ()) + { + dump (dumper::TREE) && dump ("Writing inner template parm:%d %C:%N", + inner_tag, TREE_CODE (inner), inner); + start (inner); + tree_node_bools (inner); + } + } + + tree type = NULL_TREE; + if (TREE_CODE (inner) == TYPE_DECL) + { + type = TREE_TYPE (inner); + int type_tag = insert (type); + if (streaming_p ()) + { + dump (dumper::TREE) && dump ("Writing template parm type:%d %C:%N", + type_tag, TREE_CODE (type), type); + start (type); + tree_node_bools (type); + } + } + + if (inner != parm) + { + /* This is a template-template parameter. */ + unsigned tpl_levels = 0; + tpl_header (parm, &tpl_levels); + tpl_parms_fini (parm, tpl_levels); + } + + tree_node_vals (parm); + if (inner != parm) + tree_node_vals (inner); + if (type) + { + tree_node_vals (type); + if (DECL_NAME (inner) == auto_identifier + || DECL_NAME (inner) == decltype_auto_identifier) + { + /* Placeholder auto. */ + tree_node (DECL_INITIAL (inner)); + tree_node (DECL_SIZE_UNIT (inner)); + } + } + + if (streaming_p ()) + dump (dumper::TREE) && dump ("Wrote template parm:%d %C:%N", + parm_tag, TREE_CODE (parm), parm); +} + +tree +trees_in::tpl_parm_value () +{ + tree parm = start (); + if (!parm || !tree_node_bools (parm)) + return NULL_TREE; + + int parm_tag = insert (parm); + dump (dumper::TREE) && dump ("Reading template parm:%d %C:%N", + parm_tag, TREE_CODE (parm), parm); + + tree inner = parm; + if (TREE_CODE (inner) == TEMPLATE_DECL) + { + inner = start (); + if (!inner || !tree_node_bools (inner)) + return NULL_TREE; + int inner_tag = insert (inner); + dump (dumper::TREE) && dump ("Reading inner template parm:%d %C:%N", + inner_tag, TREE_CODE (inner), inner); + DECL_TEMPLATE_RESULT (parm) = inner; + } + + tree type = NULL_TREE; + if (TREE_CODE (inner) == TYPE_DECL) + { + type = start (); + if (!type || !tree_node_bools (type)) + return NULL_TREE; + int type_tag = insert (type); + dump (dumper::TREE) && dump ("Reading template parm type:%d %C:%N", + type_tag, TREE_CODE (type), type); + + TREE_TYPE (inner) = TREE_TYPE (parm) = type; + TYPE_NAME (type) = parm; + } + + if (inner != parm) + { + /* A template template parameter. */ + unsigned tpl_levels = 0; + tpl_header (parm, &tpl_levels); + tpl_parms_fini (parm, tpl_levels); + } + + tree_node_vals (parm); + if (inner != parm) + tree_node_vals (inner); + if (type) + { + tree_node_vals (type); + if (DECL_NAME (inner) == auto_identifier + || DECL_NAME (inner) == decltype_auto_identifier) + { + /* Placeholder auto. */ + DECL_INITIAL (inner) = tree_node (); + DECL_SIZE_UNIT (inner) = tree_node (); + } + if (TYPE_CANONICAL (type)) + { + gcc_checking_assert (TYPE_CANONICAL (type) == type); + TYPE_CANONICAL (type) = canonical_type_parameter (type); + } + } + + dump (dumper::TREE) && dump ("Read template parm:%d %C:%N", + parm_tag, TREE_CODE (parm), parm); + + return parm; +} + +void +trees_out::install_entity (tree decl, depset *dep) +{ + gcc_checking_assert (streaming_p ()); + + /* Write the entity index, so we can insert it as soon as we + know this is new. */ + u (dep ? dep->cluster + 1 : 0); + if (CHECKING_P && dep) + { + /* Add it to the entity map, such that we can tell it is + part of us. */ + bool existed; + unsigned *slot = &entity_map->get_or_insert + (DECL_UID (decl), &existed); + if (existed) + /* If it existed, it should match. */ + gcc_checking_assert (decl == (*entity_ary)[*slot]); + *slot = ~dep->cluster; + } +} + +bool +trees_in::install_entity (tree decl) +{ + unsigned entity_index = u (); + if (!entity_index) + return false; + + if (entity_index > state->entity_num) + { + set_overrun (); + return false; + } + + /* Insert the real decl into the entity ary. */ + unsigned ident = state->entity_lwm + entity_index - 1; + binding_slot &elt = (*entity_ary)[ident]; + + /* See module_state::read_pendings for how this got set. */ + int pending = elt.get_lazy () & 3; + + elt = decl; + + /* And into the entity map, if it's not already there. */ + if (!DECL_LANG_SPECIFIC (decl) + || !DECL_MODULE_ENTITY_P (decl)) + { + retrofit_lang_decl (decl); + DECL_MODULE_ENTITY_P (decl) = true; + + /* Insert into the entity hash (it cannot already be there). */ + bool existed; + unsigned &slot = entity_map->get_or_insert (DECL_UID (decl), &existed); + gcc_checking_assert (!existed); + slot = ident; + } + else if (pending != 0) + { + unsigned key_ident = import_entity_index (decl); + if (pending & 1) + if (!pending_table->add (key_ident, ~ident)) + pending &= ~1; + + if (pending & 2) + if (!pending_table->add (~key_ident, ~ident)) + pending &= ~2; + } + + if (pending & 1) + DECL_MODULE_PENDING_SPECIALIZATIONS_P (decl) = true; + + if (pending & 2) + { + DECL_MODULE_PENDING_MEMBERS_P (decl) = true; + gcc_checking_assert (TREE_CODE (decl) != TEMPLATE_DECL); + } + + return true; +} + +static bool has_definition (tree decl); + +/* DECL is a decl node that must be written by value. DEP is the + decl's depset. */ + +void +trees_out::decl_value (tree decl, depset *dep) +{ + /* We should not be writing clones or template parms. */ + gcc_checking_assert (DECL_P (decl) + && !DECL_CLONED_FUNCTION_P (decl) + && !DECL_TEMPLATE_PARM_P (decl)); + + /* We should never be writing non-typedef ptrmemfuncs by value. */ + gcc_checking_assert (TREE_CODE (decl) != TYPE_DECL + || DECL_ORIGINAL_TYPE (decl) + || !TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))); + + merge_kind mk = get_merge_kind (decl, dep); + + if (CHECKING_P) + { + /* Never start in the middle of a template. */ + int use_tpl = -1; + if (tree ti = node_template_info (decl, use_tpl)) + gcc_checking_assert (TREE_CODE (TI_TEMPLATE (ti)) == OVERLOAD + || TREE_CODE (TI_TEMPLATE (ti)) == FIELD_DECL + || (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) + != decl)); + } + + if (streaming_p ()) + { + /* A new node -> tt_decl. */ + decl_val_count++; + i (tt_decl); + u (mk); + start (decl); + + if (mk != MK_unique) + { + if (!(mk & MK_template_mask) && !state->is_header ()) + { + /* Tell the importer whether this is a global module entity, + or a module entity. This bool merges into the next block + of bools. Sneaky. */ + tree o = get_originating_module_decl (decl); + bool is_mod = false; + + if (dep && dep->is_alias_tmpl_inst ()) + /* Alias template instantiations are templatey, but + found by name. */ + is_mod = false; + else if (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o)) + is_mod = true; + b (is_mod); + } + b (dep && dep->has_defn ()); + } + tree_node_bools (decl); + } + + int tag = insert (decl, WK_value); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], tag, + TREE_CODE (decl), decl, decl); + + tree inner = decl; + int inner_tag = 0; + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + if (dep && dep->is_alias_tmpl_inst ()) + inner = NULL_TREE; + else + { + inner = DECL_TEMPLATE_RESULT (decl); + inner_tag = insert (inner, WK_value); + } + + if (streaming_p ()) + { + int code = inner ? TREE_CODE (inner) : 0; + u (code); + if (inner) + { + start (inner, true); + tree_node_bools (inner); + dump (dumper::TREE) + && dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], inner_tag, + TREE_CODE (inner), inner, inner); + } + } + } + + tree type = NULL_TREE; + int type_tag = 0; + tree stub_decl = NULL_TREE; + int stub_tag = 0; + if (inner && TREE_CODE (inner) == TYPE_DECL) + { + type = TREE_TYPE (inner); + bool has_type = (type == TYPE_MAIN_VARIANT (type) + && TYPE_NAME (type) == inner); + + if (streaming_p ()) + u (has_type ? TREE_CODE (type) : 0); + + if (has_type) + { + type_tag = insert (type, WK_value); + if (streaming_p ()) + { + start (type, true); + tree_node_bools (type); + dump (dumper::TREE) + && dump ("Writing type:%d %C:%N", type_tag, + TREE_CODE (type), type); + } + + stub_decl = TYPE_STUB_DECL (type); + bool has_stub = inner != stub_decl; + if (streaming_p ()) + u (has_stub ? TREE_CODE (stub_decl) : 0); + if (has_stub) + { + stub_tag = insert (stub_decl); + if (streaming_p ()) + { + start (stub_decl, true); + tree_node_bools (stub_decl); + dump (dumper::TREE) + && dump ("Writing stub_decl:%d %C:%N", stub_tag, + TREE_CODE (stub_decl), stub_decl); + } + } + else + stub_decl = NULL_TREE; + } + else + /* Regular typedef. */ + type = NULL_TREE; + } + + /* Stream the container, we want it correctly canonicalized before + we start emitting keys for this decl. */ + tree container = decl_container (decl); + + unsigned tpl_levels = 0; + if (decl != inner) + tpl_header (decl, &tpl_levels); + if (inner && TREE_CODE (inner) == FUNCTION_DECL) + fn_parms_init (inner); + + /* Now write out the merging information, and then really + install the tag values. */ + key_mergeable (tag, mk, decl, inner, container, dep); + + if (streaming_p ()) + dump (dumper::MERGE) + && dump ("Wrote:%d's %s merge key %C:%N", tag, + merge_kind_name[mk], TREE_CODE (decl), decl); + + if (inner && TREE_CODE (inner) == FUNCTION_DECL) + fn_parms_fini (inner); + + if (!is_key_order ()) + tree_node_vals (decl); + + if (inner_tag) + { + if (!is_key_order ()) + tree_node_vals (inner); + tpl_parms_fini (decl, tpl_levels); + } + else if (!inner) + { + /* A template alias instantiation. */ + inner = DECL_TEMPLATE_RESULT (decl); + if (!is_key_order ()) + tree_node (inner); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote(%d) alias template %C:%N", + get_tag (inner), TREE_CODE (inner), inner); + inner = NULL_TREE; + } + + if (type && !is_key_order ()) + { + tree_node_vals (type); + if (stub_decl) + tree_node_vals (stub_decl); + } + + if (!is_key_order ()) + tree_node (get_constraints (decl)); + + if (streaming_p ()) + { + /* Do not stray outside this section. */ + gcc_checking_assert (!dep || dep->section == dep_hash->section); + + /* Write the entity index, so we can insert it as soon as we + know this is new. */ + install_entity (decl, dep); + } + + if (inner + && VAR_OR_FUNCTION_DECL_P (inner) + && DECL_LANG_SPECIFIC (inner) + && DECL_MODULE_ATTACHMENTS_P (inner) + && !is_key_order ()) + { + /* Stream the attached entities. */ + attachset *set = attached_table->get (DECL_UID (inner)); + unsigned num = set->num; + if (streaming_p ()) + u (num); + for (unsigned ix = 0; ix != num; ix++) + { + tree attached = set->values[ix]; + tree_node (attached); + if (streaming_p ()) + dump (dumper::MERGE) + && dump ("Written %d[%u] attached decl %N", tag, ix, attached); + } + } + + bool is_typedef = (!type && inner + && TREE_CODE (inner) == TYPE_DECL + && DECL_ORIGINAL_TYPE (inner) + && TYPE_NAME (TREE_TYPE (inner)) == inner); + if (is_typedef) + { + /* A typedef type. */ + int type_tag = insert (TREE_TYPE (inner)); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Cloned:%d typedef %C:%N", type_tag, + TREE_CODE (TREE_TYPE (inner)), TREE_TYPE (inner)); + } + + if (streaming_p () && DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)) + { + bool cloned_p + = (DECL_CHAIN (decl) && DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl))); + bool needs_vtt_parm_p + = (cloned_p && CLASSTYPE_VBASECLASSES (DECL_CONTEXT (decl))); + bool omit_inherited_parms_p + = (cloned_p && DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl) + && base_ctor_omit_inherited_parms (decl)); + unsigned flags = (int (cloned_p) << 0 + | int (needs_vtt_parm_p) << 1 + | int (omit_inherited_parms_p) << 2); + u (flags); + dump (dumper::TREE) && dump ("CDTOR %N is %scloned", + decl, cloned_p ? "" : "not "); + } + + if (streaming_p ()) + dump (dumper::TREE) && dump ("Written decl:%d %C:%N", tag, + TREE_CODE (decl), decl); + + if (!inner || NAMESPACE_SCOPE_P (inner)) + gcc_checking_assert (!inner + || !dep == (VAR_OR_FUNCTION_DECL_P (inner) + && DECL_LOCAL_DECL_P (inner))); + else if ((TREE_CODE (inner) == TYPE_DECL + && !is_typedef + && TYPE_NAME (TREE_TYPE (inner)) == inner) + || TREE_CODE (inner) == FUNCTION_DECL) + { + bool write_defn = !dep && has_definition (decl); + if (streaming_p ()) + u (write_defn); + if (write_defn) + write_definition (decl); + } +} + +tree +trees_in::decl_value () +{ + int tag = 0; + bool is_mod = false; + bool has_defn = false; + unsigned mk_u = u (); + if (mk_u >= MK_hwm || !merge_kind_name[mk_u]) + { + set_overrun (); + return NULL_TREE; + } + + unsigned saved_unused = unused; + unused = 0; + + merge_kind mk = merge_kind (mk_u); + + tree decl = start (); + if (decl) + { + if (mk != MK_unique) + { + if (!(mk & MK_template_mask) && !state->is_header ()) + /* See note in trees_out about where this bool is sequenced. */ + is_mod = b (); + + has_defn = b (); + } + + if (!tree_node_bools (decl)) + decl = NULL_TREE; + } + + /* Insert into map. */ + tag = insert (decl); + if (decl) + dump (dumper::TREE) + && dump ("Reading:%d %C", tag, TREE_CODE (decl)); + + tree inner = decl; + int inner_tag = 0; + if (decl && TREE_CODE (decl) == TEMPLATE_DECL) + { + int code = u (); + if (!code) + { + inner = NULL_TREE; + DECL_TEMPLATE_RESULT (decl) = error_mark_node; + } + else + { + inner = start (code); + if (inner && tree_node_bools (inner)) + DECL_TEMPLATE_RESULT (decl) = inner; + else + decl = NULL_TREE; + + inner_tag = insert (inner); + if (decl) + dump (dumper::TREE) + && dump ("Reading:%d %C", inner_tag, TREE_CODE (inner)); + } + } + + tree type = NULL_TREE; + int type_tag = 0; + tree stub_decl = NULL_TREE; + int stub_tag = 0; + if (decl && inner && TREE_CODE (inner) == TYPE_DECL) + { + if (unsigned type_code = u ()) + { + type = start (type_code); + if (type && tree_node_bools (type)) + { + TREE_TYPE (inner) = type; + TYPE_NAME (type) = inner; + } + else + decl = NULL_TREE; + + type_tag = insert (type); + if (decl) + dump (dumper::TREE) + && dump ("Reading type:%d %C", type_tag, TREE_CODE (type)); + + if (unsigned stub_code = u ()) + { + stub_decl = start (stub_code); + if (stub_decl && tree_node_bools (stub_decl)) + { + TREE_TYPE (stub_decl) = type; + TYPE_STUB_DECL (type) = stub_decl; + } + else + decl = NULL_TREE; + + stub_tag = insert (stub_decl); + if (decl) + dump (dumper::TREE) + && dump ("Reading stub_decl:%d %C", stub_tag, + TREE_CODE (stub_decl)); + } + } + } + + if (!decl) + { + bail: + if (inner_tag != 0) + back_refs[~inner_tag] = NULL_TREE; + if (type_tag != 0) + back_refs[~type_tag] = NULL_TREE; + if (stub_tag != 0) + back_refs[~stub_tag] = NULL_TREE; + if (tag != 0) + back_refs[~tag] = NULL_TREE; + set_overrun (); + /* Bail. */ + unused = saved_unused; + return NULL_TREE; + } + + /* Read the container, to ensure it's already been streamed in. */ + tree container = decl_container (); + unsigned tpl_levels = 0; + + /* Figure out if this decl is already known about. */ + int parm_tag = 0; + + if (decl != inner) + if (!tpl_header (decl, &tpl_levels)) + goto bail; + if (inner && TREE_CODE (inner) == FUNCTION_DECL) + parm_tag = fn_parms_init (inner); + + tree existing = key_mergeable (tag, mk, decl, inner, type, container, is_mod); + tree existing_inner = existing; + if (existing) + { + if (existing == error_mark_node) + goto bail; + + if (TREE_CODE (STRIP_TEMPLATE (existing)) == TYPE_DECL) + { + tree etype = TREE_TYPE (existing); + if (TYPE_LANG_SPECIFIC (etype) + && COMPLETE_TYPE_P (etype) + && !CLASSTYPE_MEMBER_VEC (etype)) + /* Give it a member vec, we're likely gonna be looking + inside it. */ + set_class_bindings (etype, -1); + } + + /* Install the existing decl into the back ref array. */ + register_duplicate (decl, existing); + back_refs[~tag] = existing; + if (inner_tag != 0) + { + existing_inner = DECL_TEMPLATE_RESULT (existing); + back_refs[~inner_tag] = existing_inner; + } + + if (type_tag != 0) + { + tree existing_type = TREE_TYPE (existing); + back_refs[~type_tag] = existing_type; + if (stub_tag != 0) + back_refs[~stub_tag] = TYPE_STUB_DECL (existing_type); + } + } + + if (parm_tag) + fn_parms_fini (parm_tag, inner, existing_inner, has_defn); + + if (!tree_node_vals (decl)) + goto bail; + + if (inner_tag) + { + gcc_checking_assert (DECL_TEMPLATE_RESULT (decl) == inner); + + if (!tree_node_vals (inner)) + goto bail; + + if (!tpl_parms_fini (decl, tpl_levels)) + goto bail; + } + else if (!inner) + { + inner = tree_node (); + DECL_TEMPLATE_RESULT (decl) = inner; + TREE_TYPE (decl) = TREE_TYPE (inner); + dump (dumper::TREE) + && dump ("Read alias template %C:%N", TREE_CODE (inner), inner); + inner = NULL_TREE; + } + + if (type && (!tree_node_vals (type) + || (stub_decl && !tree_node_vals (stub_decl)))) + goto bail; + + tree constraints = tree_node (); + + dump (dumper::TREE) && dump ("Read:%d %C:%N", tag, TREE_CODE (decl), decl); + + /* Regular typedefs will have a NULL TREE_TYPE at this point. */ + bool is_typedef = (!type && inner + && TREE_CODE (inner) == TYPE_DECL + && DECL_ORIGINAL_TYPE (inner) + && !TREE_TYPE (inner)); + + existing = back_refs[~tag]; + bool installed = install_entity (existing); + bool is_new = existing == decl; + + if (inner + && VAR_OR_FUNCTION_DECL_P (inner) + && DECL_LANG_SPECIFIC (inner) + && DECL_MODULE_ATTACHMENTS_P (inner)) + { + /* Read and maybe install the attached entities. */ + attachset *set + = attached_table->get (DECL_UID (STRIP_TEMPLATE (existing))); + unsigned num = u (); + if (!is_new == !set) + set_overrun (); + if (is_new) + set = attached_table->create (DECL_UID (inner), num, NULL_TREE); + for (unsigned ix = 0; !get_overrun () && ix != num; ix++) + { + tree attached = tree_node (); + dump (dumper::MERGE) + && dump ("Read %d[%u] %s attached decl %N", tag, ix, + is_new ? "new" : "matched", attached); + if (is_new) + set->values[ix] = attached; + else if (set->values[ix] != attached) + set_overrun (); + } + } + + if (is_new) + { + /* A newly discovered node. */ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl)) + /* Mark this identifier as naming a virtual function -- + lookup_overrides relies on this optimization. */ + IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = true; + + if (installed) + { + /* Mark the entity as imported and add it to the entity + array and map. */ + retrofit_lang_decl (decl); + DECL_MODULE_IMPORT_P (decl) = true; + if (inner_tag) + { + retrofit_lang_decl (inner); + DECL_MODULE_IMPORT_P (inner) = true; + } + } + + if (constraints) + set_constraints (decl, constraints); + + if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl)) + { + decl = cache_integer_cst (decl, true); + back_refs[~tag] = decl; + } + + if (is_typedef) + { + /* Frob it to be ready for cloning. */ + TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner); + DECL_ORIGINAL_TYPE (inner) = NULL_TREE; + set_underlying_type (inner); + } + + if (inner_tag) + /* Set the TEMPLATE_DECL's type. */ + TREE_TYPE (decl) = TREE_TYPE (inner); + + /* The late insertion of an alias here or an implicit member + (next block), is ok, because we ensured that all imports were + loaded up before we started this cluster. Thus an insertion + from some other import cannot have happened between the + merged insertion above and these insertions down here. */ + if (mk == MK_alias_spec) + { + /* Insert into type table. */ + tree ti = DECL_TEMPLATE_INFO (inner); + spec_entry elt = + {TI_TEMPLATE (ti), TI_ARGS (ti), TREE_TYPE (inner)}; + tree texist = match_mergeable_specialization (false, &elt); + if (texist) + set_overrun (); + } + + if (DECL_ARTIFICIAL (decl) + && TREE_CODE (decl) == FUNCTION_DECL + && !DECL_TEMPLATE_INFO (decl) + && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)) + && TYPE_SIZE (DECL_CONTEXT (decl)) + && !DECL_THUNK_P (decl)) + /* A new implicit member function, when the class is + complete. This means the importee declared it, and + we must now add it to the class. Note that implicit + member fns of template instantiations do not themselves + look like templates. */ + if (!install_implicit_member (inner)) + set_overrun (); + } + else + { + /* DECL is the to-be-discarded decl. Its internal pointers will + be to the EXISTING's structure. Frob it to point to its + own other structures, so loading its definition will alter + it, and not the existing decl. */ + dump (dumper::MERGE) && dump ("Deduping %N", existing); + + if (inner_tag) + DECL_TEMPLATE_RESULT (decl) = inner; + + if (type) + { + /* Point at the to-be-discarded type & decl. */ + TYPE_NAME (type) = inner; + TREE_TYPE (inner) = type; + + TYPE_STUB_DECL (type) = stub_decl ? stub_decl : inner; + if (stub_decl) + TREE_TYPE (stub_decl) = type; + } + + if (inner_tag) + /* Set the TEMPLATE_DECL's type. */ + TREE_TYPE (decl) = TREE_TYPE (inner); + + if (!is_matching_decl (existing, decl, is_typedef)) + unmatched_duplicate (existing); + + /* And our result is the existing node. */ + decl = existing; + } + + if (is_typedef) + { + /* Insert the type into the array now. */ + tag = insert (TREE_TYPE (decl)); + dump (dumper::TREE) + && dump ("Cloned:%d typedef %C:%N", + tag, TREE_CODE (TREE_TYPE (decl)), TREE_TYPE (decl)); + } + + unused = saved_unused; + + if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)) + { + unsigned flags = u (); + + if (is_new) + { + bool cloned_p = flags & 1; + dump (dumper::TREE) && dump ("CDTOR %N is %scloned", + decl, cloned_p ? "" : "not "); + if (cloned_p) + build_cdtor_clones (decl, flags & 2, flags & 4, + /* Update the member vec, if there is + one (we're in a different cluster + to the class defn). */ + CLASSTYPE_MEMBER_VEC (DECL_CONTEXT (decl))); + } + } + + if (inner + && !NAMESPACE_SCOPE_P (inner) + && ((TREE_CODE (inner) == TYPE_DECL + && !is_typedef + && TYPE_NAME (TREE_TYPE (inner)) == inner) + || TREE_CODE (inner) == FUNCTION_DECL) + && u ()) + read_definition (decl); + + return decl; +} + +/* DECL is an unnameable member of CTX. Return a suitable identifying + index. */ + +static unsigned +get_field_ident (tree ctx, tree decl) +{ + gcc_checking_assert (TREE_CODE (decl) == USING_DECL + || !DECL_NAME (decl) + || IDENTIFIER_ANON_P (DECL_NAME (decl))); + + unsigned ix = 0; + for (tree fields = TYPE_FIELDS (ctx); + fields; fields = DECL_CHAIN (fields)) + { + if (fields == decl) + return ix; + + if (DECL_CONTEXT (fields) == ctx + && (TREE_CODE (fields) == USING_DECL + || (TREE_CODE (fields) == FIELD_DECL + && (!DECL_NAME (fields) + || IDENTIFIER_ANON_P (DECL_NAME (fields)))))) + /* Count this field. */ + ix++; + } + gcc_unreachable (); +} + +static tree +lookup_field_ident (tree ctx, unsigned ix) +{ + for (tree fields = TYPE_FIELDS (ctx); + fields; fields = DECL_CHAIN (fields)) + if (DECL_CONTEXT (fields) == ctx + && (TREE_CODE (fields) == USING_DECL + || (TREE_CODE (fields) == FIELD_DECL + && (!DECL_NAME (fields) + || IDENTIFIER_ANON_P (DECL_NAME (fields)))))) + if (!ix--) + return fields; + + return NULL_TREE; +} + +/* Reference DECL. REF indicates the walk kind we are performing. + Return true if we should write this decl by value. */ + +bool +trees_out::decl_node (tree decl, walk_kind ref) +{ + gcc_checking_assert (DECL_P (decl) && !DECL_TEMPLATE_PARM_P (decl) + && DECL_CONTEXT (decl)); + + if (ref == WK_value) + { + depset *dep = dep_hash->find_dependency (decl); + decl_value (decl, dep); + return false; + } + + switch (TREE_CODE (decl)) + { + default: + break; + + case FUNCTION_DECL: + gcc_checking_assert (!DECL_LOCAL_DECL_P (decl)); + break; + + case RESULT_DECL: + /* Unlike PARM_DECLs, RESULT_DECLs are only generated and + referenced when we're inside the function itself. */ + return true; + + case PARM_DECL: + { + if (streaming_p ()) + i (tt_parm); + tree_node (DECL_CONTEXT (decl)); + if (streaming_p ()) + { + /* That must have put this in the map. */ + walk_kind ref = ref_node (decl); + if (ref != WK_none) + // FIXME:OPTIMIZATION We can wander into bits of the + // template this was instantiated from. For instance + // deferred noexcept and default parms. Currently we'll + // end up cloning those bits of tree. It would be nice + // to reference those specific nodes. I think putting + // those things in the map when we reference their + // template by name. See the note in add_indirects. + return true; + + dump (dumper::TREE) + && dump ("Wrote %s reference %N", + TREE_CODE (decl) == PARM_DECL ? "parameter" : "result", + decl); + } + } + return false; + + case IMPORTED_DECL: + /* This describes a USING_DECL to the ME's debug machinery. It + originates from the fortran FE, and has nothing to do with + C++ modules. */ + return true; + + case LABEL_DECL: + return true; + + case CONST_DECL: + { + /* If I end up cloning enum decls, implementing C++20 using + E::v, this will need tweaking. */ + if (streaming_p ()) + i (tt_enum_decl); + tree ctx = DECL_CONTEXT (decl); + gcc_checking_assert (TREE_CODE (ctx) == ENUMERAL_TYPE); + tree_node (ctx); + tree_node (DECL_NAME (decl)); + + int tag = insert (decl); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote enum decl:%d %C:%N", tag, TREE_CODE (decl), decl); + return false; + } + break; + + case USING_DECL: + if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) + break; + /* FALLTHROUGH */ + + case FIELD_DECL: + { + if (streaming_p ()) + i (tt_data_member); + + tree ctx = DECL_CONTEXT (decl); + tree_node (ctx); + + tree name = NULL_TREE; + + if (TREE_CODE (decl) == USING_DECL) + ; + else + { + name = DECL_NAME (decl); + if (name && IDENTIFIER_ANON_P (name)) + name = NULL_TREE; + } + + tree_node (name); + if (!name && streaming_p ()) + { + unsigned ix = get_field_ident (ctx, decl); + u (ix); + } + + int tag = insert (decl); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote member:%d %C:%N", tag, TREE_CODE (decl), decl); + return false; + } + break; + + case VAR_DECL: + gcc_checking_assert (!DECL_LOCAL_DECL_P (decl)); + if (DECL_VTABLE_OR_VTT_P (decl)) + { + /* VTT or VTABLE, they are all on the vtables list. */ + tree ctx = CP_DECL_CONTEXT (decl); + tree vtable = CLASSTYPE_VTABLES (ctx); + for (unsigned ix = 0; ; vtable = DECL_CHAIN (vtable), ix++) + if (vtable == decl) + { + gcc_checking_assert (DECL_VIRTUAL_P (decl)); + if (streaming_p ()) + { + u (tt_vtable); + u (ix); + dump (dumper::TREE) + && dump ("Writing vtable %N[%u]", ctx, ix); + } + tree_node (ctx); + return false; + } + gcc_unreachable (); + } + + if (DECL_TINFO_P (decl)) + { + tinfo: + /* A typeinfo, tt_tinfo_typedef or tt_tinfo_var. */ + bool is_var = TREE_CODE (decl) == VAR_DECL; + tree type = TREE_TYPE (decl); + unsigned ix = get_pseudo_tinfo_index (type); + if (streaming_p ()) + { + i (is_var ? tt_tinfo_var : tt_tinfo_typedef); + u (ix); + } + + if (is_var) + { + /* We also need the type it is for and mangled name, so + the reader doesn't need to complete the type (which + would break section ordering). The type it is for is + stashed on the name's TREE_TYPE. */ + tree name = DECL_NAME (decl); + tree_node (name); + type = TREE_TYPE (name); + tree_node (type); + } + + int tag = insert (decl); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote tinfo_%s:%d %u %N", is_var ? "var" : "type", + tag, ix, type); + + if (!is_var) + { + tag = insert (type); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote tinfo_type:%d %u %N", tag, ix, type); + } + return false; + } + break; + + case TYPE_DECL: + if (DECL_TINFO_P (decl)) + goto tinfo; + break; + } + + if (DECL_THUNK_P (decl)) + { + /* Thunks are similar to binfos -- write the thunked-to decl and + then thunk-specific key info. */ + if (streaming_p ()) + { + i (tt_thunk); + i (THUNK_FIXED_OFFSET (decl)); + } + + tree target = decl; + while (DECL_THUNK_P (target)) + target = THUNK_TARGET (target); + tree_node (target); + tree_node (THUNK_VIRTUAL_OFFSET (decl)); + int tag = insert (decl); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote:%d thunk %N to %N", tag, DECL_NAME (decl), target); + return false; + } + + if (DECL_CLONED_FUNCTION_P (decl)) + { + tree target = get_clone_target (decl); + if (streaming_p ()) + i (tt_clone_ref); + + tree_node (target); + tree_node (DECL_NAME (decl)); + int tag = insert (decl); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote:%d clone %N of %N", tag, DECL_NAME (decl), target); + return false; + } + + /* Everything left should be a thing that is in the entity table. + Mostly things that can be defined outside of their (original + declaration) context. */ + gcc_checking_assert (TREE_CODE (decl) == TEMPLATE_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == USING_DECL + || TREE_CODE (decl) == CONCEPT_DECL + || TREE_CODE (decl) == NAMESPACE_DECL); + + int use_tpl = -1; + tree ti = node_template_info (decl, use_tpl); + tree tpl = NULL_TREE; + + /* If this is the TEMPLATE_DECL_RESULT of a TEMPLATE_DECL, get the + TEMPLATE_DECL. Note TI_TEMPLATE is not a TEMPLATE_DECL for + (some) friends, so we need to check that. */ + // FIXME: Should local friend template specializations be by value? + // They don't get idents so we'll never know they're imported, but I + // think we can only reach them from the TU that defines the + // befriending class? + if (ti && TREE_CODE (TI_TEMPLATE (ti)) == TEMPLATE_DECL + && DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == decl) + { + tpl = TI_TEMPLATE (ti); + partial_template: + if (streaming_p ()) + { + i (tt_template); + dump (dumper::TREE) + && dump ("Writing implicit template %C:%N%S", + TREE_CODE (tpl), tpl, tpl); + } + tree_node (tpl); + + /* Streaming TPL caused us to visit DECL and maybe its type. */ + gcc_checking_assert (TREE_VISITED (decl)); + if (DECL_IMPLICIT_TYPEDEF_P (decl)) + gcc_checking_assert (TREE_VISITED (TREE_TYPE (decl))); + return false; + } + + tree ctx = CP_DECL_CONTEXT (decl); + depset *dep = NULL; + if (streaming_p ()) + dep = dep_hash->find_dependency (decl); + else if (TREE_CODE (ctx) != FUNCTION_DECL + || TREE_CODE (decl) == TEMPLATE_DECL + || (dep_hash->sneakoscope && DECL_IMPLICIT_TYPEDEF_P (decl)) + || (DECL_LANG_SPECIFIC (decl) + && DECL_MODULE_IMPORT_P (decl))) + dep = dep_hash->add_dependency (decl, + TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl) + ? depset::EK_NAMESPACE : depset::EK_DECL); + + if (!dep) + { + /* Some internal entity of context. Do by value. */ + decl_value (decl, NULL); + return false; + } + + if (dep->get_entity_kind () == depset::EK_REDIRECT) + { + /* The DECL_TEMPLATE_RESULT of a partial specialization. + Write the partial specialization's template. */ + depset *redirect = dep->deps[0]; + gcc_checking_assert (redirect->get_entity_kind () == depset::EK_PARTIAL); + tpl = redirect->get_entity (); + goto partial_template; + } + + if (streaming_p ()) + { + /* Locate the entity. */ + unsigned index = dep->cluster; + unsigned import = 0; + + if (dep->is_import ()) + import = dep->section; + else if (CHECKING_P) + /* It should be what we put there. */ + gcc_checking_assert (index == ~import_entity_index (decl)); + +#if CHECKING_P + if (importedness) + gcc_assert (!import == (importedness < 0)); +#endif + i (tt_entity); + u (import); + u (index); + } + + int tag = insert (decl); + if (streaming_p () && dump (dumper::TREE)) + { + char const *kind = "import"; + module_state *from = (*modules)[0]; + if (dep->is_import ()) + /* Rediscover the unremapped index. */ + from = import_entity_module (import_entity_index (decl)); + else + { + tree o = get_originating_module_decl (decl); + kind = (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o) + ? "purview" : "GMF"); + } + dump ("Wrote %s:%d %C:%N@%M", kind, + tag, TREE_CODE (decl), decl, from); + } + + add_indirects (decl); + + return false; +} + +void +trees_out::type_node (tree type) +{ + gcc_assert (TYPE_P (type)); + + tree root = (TYPE_NAME (type) + ? TREE_TYPE (TYPE_NAME (type)) : TYPE_MAIN_VARIANT (type)); + + if (type != root) + { + if (streaming_p ()) + i (tt_variant_type); + tree_node (root); + + int flags = -1; + + if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + { + int quals = type_memfn_quals (type); + int rquals = type_memfn_rqual (type); + tree raises = TYPE_RAISES_EXCEPTIONS (type); + bool late = TYPE_HAS_LATE_RETURN_TYPE (type); + + if (raises != TYPE_RAISES_EXCEPTIONS (root) + || rquals != type_memfn_rqual (root) + || quals != type_memfn_quals (root) + || late != TYPE_HAS_LATE_RETURN_TYPE (root)) + flags = rquals | (int (late) << 2) | (quals << 3); + } + else + { + if (TYPE_USER_ALIGN (type)) + flags = exact_log2 (TYPE_ALIGN (type)); + } + + if (streaming_p ()) + i (flags); + + if (flags < 0) + ; + else if (TREE_CODE (type) == FUNCTION_TYPE + || TREE_CODE (type) == METHOD_TYPE) + { + tree raises = TYPE_RAISES_EXCEPTIONS (type); + if (raises == TYPE_RAISES_EXCEPTIONS (root)) + raises = error_mark_node; + tree_node (raises); + } + + tree_node (TYPE_ATTRIBUTES (type)); + + if (streaming_p ()) + { + /* Qualifiers. */ + int rquals = cp_type_quals (root); + int quals = cp_type_quals (type); + if (quals == rquals) + quals = -1; + i (quals); + } + + if (ref_node (type) != WK_none) + { + int tag = insert (type); + if (streaming_p ()) + { + i (0); + dump (dumper::TREE) + && dump ("Wrote:%d variant type %C", tag, TREE_CODE (type)); + } + } + return; + } + + if (tree name = TYPE_NAME (type)) + if ((TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)) + || DECL_TEMPLATE_PARM_P (name) + || TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + { + /* We can meet template parms that we didn't meet in the + tpl_parms walk, because we're referring to a derived type + that was previously constructed from equivalent template + parms. */ + if (streaming_p ()) + { + i (tt_typedef_type); + dump (dumper::TREE) + && dump ("Writing %stypedef %C:%N", + DECL_IMPLICIT_TYPEDEF_P (name) ? "implicit " : "", + TREE_CODE (name), name); + } + tree_node (name); + if (streaming_p ()) + dump (dumper::TREE) && dump ("Wrote typedef %C:%N%S", + TREE_CODE (name), name, name); + gcc_checking_assert (TREE_VISITED (type)); + return; + } + + if (TYPE_PTRMEMFUNC_P (type)) + { + /* This is a distinct type node, masquerading as a structure. */ + tree fn_type = TYPE_PTRMEMFUNC_FN_TYPE (type); + if (streaming_p ()) + i (tt_ptrmem_type); + tree_node (fn_type); + int tag = insert (type); + if (streaming_p ()) + dump (dumper::TREE) && dump ("Written:%d ptrmem type", tag); + return; + } + + if (streaming_p ()) + { + u (tt_derived_type); + u (TREE_CODE (type)); + } + + tree_node (TREE_TYPE (type)); + switch (TREE_CODE (type)) + { + default: + /* We should never meet a type here that is indescribable in + terms of other types. */ + gcc_unreachable (); + + case ARRAY_TYPE: + tree_node (TYPE_DOMAIN (type)); + if (streaming_p ()) + /* Dependent arrays are constructed with TYPE_DEPENENT_P + already set. */ + u (TYPE_DEPENDENT_P (type)); + break; + + case COMPLEX_TYPE: + /* No additional data. */ + break; + + case BOOLEAN_TYPE: + /* A non-standard boolean type. */ + if (streaming_p ()) + u (TYPE_PRECISION (type)); + break; + + case INTEGER_TYPE: + if (TREE_TYPE (type)) + { + /* A range type (representing an array domain). */ + tree_node (TYPE_MIN_VALUE (type)); + tree_node (TYPE_MAX_VALUE (type)); + } + else + { + /* A new integral type (representing a bitfield). */ + if (streaming_p ()) + { + unsigned prec = TYPE_PRECISION (type); + bool unsigned_p = TYPE_UNSIGNED (type); + + u ((prec << 1) | unsigned_p); + } + } + break; + + case METHOD_TYPE: + case FUNCTION_TYPE: + { + gcc_checking_assert (type_memfn_rqual (type) == REF_QUAL_NONE); + + tree arg_types = TYPE_ARG_TYPES (type); + if (TREE_CODE (type) == METHOD_TYPE) + { + tree_node (TREE_TYPE (TREE_VALUE (arg_types))); + arg_types = TREE_CHAIN (arg_types); + } + tree_node (arg_types); + } + break; + + case OFFSET_TYPE: + tree_node (TYPE_OFFSET_BASETYPE (type)); + break; + + case POINTER_TYPE: + /* No additional data. */ + break; + + case REFERENCE_TYPE: + if (streaming_p ()) + u (TYPE_REF_IS_RVALUE (type)); + break; + + case DECLTYPE_TYPE: + case TYPEOF_TYPE: + case UNDERLYING_TYPE: + tree_node (TYPE_VALUES_RAW (type)); + if (TREE_CODE (type) == DECLTYPE_TYPE) + /* We stash a whole bunch of things into decltype's + flags. */ + if (streaming_p ()) + tree_node_bools (type); + break; + + case TYPE_ARGUMENT_PACK: + /* No additional data. */ + break; + + case TYPE_PACK_EXPANSION: + if (streaming_p ()) + u (PACK_EXPANSION_LOCAL_P (type)); + tree_node (PACK_EXPANSION_PARAMETER_PACKS (type)); + break; + + case TYPENAME_TYPE: + { + tree_node (TYPE_CONTEXT (type)); + tree_node (DECL_NAME (TYPE_NAME (type))); + tree_node (TYPENAME_TYPE_FULLNAME (type)); + if (streaming_p ()) + { + enum tag_types tag_type = none_type; + if (TYPENAME_IS_ENUM_P (type)) + tag_type = enum_type; + else if (TYPENAME_IS_CLASS_P (type)) + tag_type = class_type; + u (int (tag_type)); + } + } + break; + + case UNBOUND_CLASS_TEMPLATE: + { + tree decl = TYPE_NAME (type); + tree_node (DECL_CONTEXT (decl)); + tree_node (DECL_NAME (decl)); + tree_node (DECL_TEMPLATE_PARMS (decl)); + } + break; + + case VECTOR_TYPE: + if (streaming_p ()) + { + poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (type); + /* to_constant asserts that only coeff[0] is of interest. */ + wu (static_cast<unsigned HOST_WIDE_INT> (nunits.to_constant ())); + } + break; + } + + /* We may have met the type during emitting the above. */ + if (ref_node (type) != WK_none) + { + int tag = insert (type); + if (streaming_p ()) + { + i (0); + dump (dumper::TREE) + && dump ("Wrote:%d derived type %C", tag, TREE_CODE (type)); + } + } + + return; +} + +/* T is (mostly*) a non-mergeable node that must be written by value. + The mergeable case is a BINFO, which are as-if DECLSs. */ + +void +trees_out::tree_value (tree t) +{ + /* We should never be writing a type by value. tree_type should + have streamed it, or we're going via its TYPE_DECL. */ + gcc_checking_assert (!TYPE_P (t)); + + if (DECL_P (t)) + /* No template, type, var or function, except anonymous + non-context vars. */ + gcc_checking_assert ((TREE_CODE (t) != TEMPLATE_DECL + && TREE_CODE (t) != TYPE_DECL + && (TREE_CODE (t) != VAR_DECL + || (!DECL_NAME (t) && !DECL_CONTEXT (t))) + && TREE_CODE (t) != FUNCTION_DECL)); + + if (streaming_p ()) + { + /* A new node -> tt_node. */ + tree_val_count++; + i (tt_node); + start (t); + tree_node_bools (t); + } + + if (TREE_CODE (t) == TREE_BINFO) + /* Binfos are decl-like and need merging information. */ + binfo_mergeable (t); + + int tag = insert (t, WK_value); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Writing tree:%d %C:%N", tag, TREE_CODE (t), t); + + tree_node_vals (t); + + if (streaming_p ()) + dump (dumper::TREE) && dump ("Written tree:%d %C:%N", tag, TREE_CODE (t), t); +} + +tree +trees_in::tree_value () +{ + tree t = start (); + if (!t || !tree_node_bools (t)) + return NULL_TREE; + + tree existing = t; + if (TREE_CODE (t) == TREE_BINFO) + { + tree type; + unsigned ix = binfo_mergeable (&type); + if (TYPE_BINFO (type)) + { + /* We already have a definition, this must be a duplicate. */ + dump (dumper::MERGE) + && dump ("Deduping binfo %N[%u]", type, ix); + existing = TYPE_BINFO (type); + while (existing && ix) + existing = TREE_CHAIN (existing); + if (existing) + register_duplicate (t, existing); + else + /* Error, mismatch -- diagnose in read_class_def's + checking. */ + existing = t; + } + } + + /* Insert into map. */ + int tag = insert (existing); + dump (dumper::TREE) + && dump ("Reading tree:%d %C", tag, TREE_CODE (t)); + + if (!tree_node_vals (t)) + { + back_refs[~tag] = NULL_TREE; + set_overrun (); + /* Bail. */ + return NULL_TREE; + } + + dump (dumper::TREE) && dump ("Read tree:%d %C:%N", tag, TREE_CODE (t), t); + + if (TREE_CODE (existing) == INTEGER_CST && !TREE_OVERFLOW (existing)) + { + existing = cache_integer_cst (t, true); + back_refs[~tag] = existing; + } + + return existing; +} + +/* Stream out tree node T. We automatically create local back + references, which is essentially a single pass lisp + self-referential structure pretty-printer. */ + +void +trees_out::tree_node (tree t) +{ + dump.indent (); + walk_kind ref = ref_node (t); + if (ref == WK_none) + goto done; + + if (ref != WK_normal) + goto skip_normal; + + if (TREE_CODE (t) == IDENTIFIER_NODE) + { + /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id. */ + int code = tt_id; + if (IDENTIFIER_ANON_P (t)) + code = IDENTIFIER_LAMBDA_P (t) ? tt_lambda_id : tt_anon_id; + else if (IDENTIFIER_CONV_OP_P (t)) + code = tt_conv_id; + + if (streaming_p ()) + i (code); + + if (code == tt_conv_id) + { + tree type = TREE_TYPE (t); + gcc_checking_assert (type || t == conv_op_identifier); + tree_node (type); + } + else if (code == tt_id && streaming_p ()) + str (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t)); + + int tag = insert (t); + if (streaming_p ()) + { + /* We know the ordering of the 4 id tags. */ + static const char *const kinds[] = + {"", "conv_op ", "anon ", "lambda "}; + dump (dumper::TREE) + && dump ("Written:%d %sidentifier:%N", tag, + kinds[code - tt_id], + code == tt_conv_id ? TREE_TYPE (t) : t); + } + goto done; + } + + if (TREE_CODE (t) == TREE_BINFO) + { + /* A BINFO -> tt_binfo. + We must do this by reference. We stream the binfo tree + itself when streaming its owning RECORD_TYPE. That we got + here means the dominating type is not in this SCC. */ + if (streaming_p ()) + i (tt_binfo); + binfo_mergeable (t); + gcc_checking_assert (!TREE_VISITED (t)); + int tag = insert (t); + if (streaming_p ()) + dump (dumper::TREE) && dump ("Inserting binfo:%d %N", tag, t); + goto done; + } + + if (TREE_CODE (t) == INTEGER_CST + && !TREE_OVERFLOW (t) + && TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE) + { + /* An integral constant of enumeral type. See if it matches one + of the enumeration values. */ + for (tree values = TYPE_VALUES (TREE_TYPE (t)); + values; values = TREE_CHAIN (values)) + { + tree decl = TREE_VALUE (values); + if (tree_int_cst_equal (DECL_INITIAL (decl), t)) + { + if (streaming_p ()) + u (tt_enum_value); + tree_node (decl); + dump (dumper::TREE) && dump ("Written enum value %N", decl); + goto done; + } + } + /* It didn't match. We'll write it a an explicit INTEGER_CST + node. */ + } + + if (TYPE_P (t)) + { + type_node (t); + goto done; + } + + if (DECL_P (t)) + { + if (DECL_TEMPLATE_PARM_P (t)) + { + tpl_parm_value (t); + goto done; + } + + if (!DECL_CONTEXT (t)) + { + /* There are a few cases of decls with no context. We'll write + these by value, but first assert they are cases we expect. */ + gcc_checking_assert (ref == WK_normal); + switch (TREE_CODE (t)) + { + default: gcc_unreachable (); + + case LABEL_DECL: + /* CASE_LABEL_EXPRs contain uncontexted LABEL_DECLs. */ + gcc_checking_assert (!DECL_NAME (t)); + break; + + case VAR_DECL: + /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs. */ + gcc_checking_assert (!DECL_NAME (t) + && DECL_ARTIFICIAL (t)); + break; + + case PARM_DECL: + /* REQUIRES_EXPRs have a tree list of uncontexted + PARM_DECLS. It'd be nice if they had a + distinguishing flag to double check. */ + break; + } + goto by_value; + } + } + + skip_normal: + if (DECL_P (t) && !decl_node (t, ref)) + goto done; + + /* Otherwise by value */ + by_value: + tree_value (t); + + done: + /* And, breath out. */ + dump.outdent (); +} + +/* Stream in a tree node. */ + +tree +trees_in::tree_node (bool is_use) +{ + if (get_overrun ()) + return NULL_TREE; + + dump.indent (); + int tag = i (); + tree res = NULL_TREE; + switch (tag) + { + default: + /* backref, pull it out of the map. */ + res = back_ref (tag); + break; + + case tt_null: + /* NULL_TREE. */ + break; + + case tt_fixed: + /* A fixed ref, find it in the fixed_ref array. */ + { + unsigned fix = u (); + if (fix < (*fixed_trees).length ()) + { + res = (*fixed_trees)[fix]; + dump (dumper::TREE) && dump ("Read fixed:%u %C:%N%S", fix, + TREE_CODE (res), res, res); + } + + if (!res) + set_overrun (); + } + break; + + case tt_parm: + { + tree fn = tree_node (); + if (fn && TREE_CODE (fn) == FUNCTION_DECL) + res = tree_node (); + if (res) + dump (dumper::TREE) + && dump ("Read %s reference %N", + TREE_CODE (res) == PARM_DECL ? "parameter" : "result", + res); + } + break; + + case tt_node: + /* A new node. Stream it in. */ + res = tree_value (); + break; + + case tt_decl: + /* A new decl. Stream it in. */ + res = decl_value (); + break; + + case tt_tpl_parm: + /* A template parameter. Stream it in. */ + res = tpl_parm_value (); + break; + + case tt_id: + /* An identifier node. */ + { + size_t l; + const char *chars = str (&l); + res = get_identifier_with_length (chars, l); + int tag = insert (res); + dump (dumper::TREE) + && dump ("Read identifier:%d %N", tag, res); + } + break; + + case tt_conv_id: + /* A conversion operator. Get the type and recreate the + identifier. */ + { + tree type = tree_node (); + if (!get_overrun ()) + { + res = type ? make_conv_op_name (type) : conv_op_identifier; + int tag = insert (res); + dump (dumper::TREE) + && dump ("Created conv_op:%d %S for %N", tag, res, type); + } + } + break; + + case tt_anon_id: + case tt_lambda_id: + /* An anonymous or lambda id. */ + { + res = make_anon_name (); + if (tag == tt_lambda_id) + IDENTIFIER_LAMBDA_P (res) = true; + int tag = insert (res); + dump (dumper::TREE) + && dump ("Read %s identifier:%d %N", + IDENTIFIER_LAMBDA_P (res) ? "lambda" : "anon", tag, res); + } + break; + + case tt_typedef_type: + res = tree_node (); + if (res) + { + dump (dumper::TREE) + && dump ("Read %stypedef %C:%N", + DECL_IMPLICIT_TYPEDEF_P (res) ? "implicit " : "", + TREE_CODE (res), res); + res = TREE_TYPE (res); + } + break; + + case tt_derived_type: + /* A type derived from some other type. */ + { + enum tree_code code = tree_code (u ()); + res = tree_node (); + + switch (code) + { + default: + set_overrun (); + break; + + case ARRAY_TYPE: + { + tree domain = tree_node (); + int dep = u (); + if (!get_overrun ()) + res = build_cplus_array_type (res, domain, dep); + } + break; + + case COMPLEX_TYPE: + if (!get_overrun ()) + res = build_complex_type (res); + break; + + case BOOLEAN_TYPE: + { + unsigned precision = u (); + if (!get_overrun ()) + res = build_nonstandard_boolean_type (precision); + } + break; + + case INTEGER_TYPE: + if (res) + { + /* A range type (representing an array domain). */ + tree min = tree_node (); + tree max = tree_node (); + + if (!get_overrun ()) + res = build_range_type (res, min, max); + } + else + { + /* A new integral type (representing a bitfield). */ + unsigned enc = u (); + if (!get_overrun ()) + res = build_nonstandard_integer_type (enc >> 1, enc & 1); + } + break; + + case FUNCTION_TYPE: + case METHOD_TYPE: + { + tree klass = code == METHOD_TYPE ? tree_node () : NULL_TREE; + tree args = tree_node (); + if (!get_overrun ()) + { + if (klass) + res = build_method_type_directly (klass, res, args); + else + res = build_function_type (res, args); + } + } + break; + + case OFFSET_TYPE: + { + tree base = tree_node (); + if (!get_overrun ()) + res = build_offset_type (base, res); + } + break; + + case POINTER_TYPE: + if (!get_overrun ()) + res = build_pointer_type (res); + break; + + case REFERENCE_TYPE: + { + bool rval = bool (u ()); + if (!get_overrun ()) + res = cp_build_reference_type (res, rval); + } + break; + + case DECLTYPE_TYPE: + case TYPEOF_TYPE: + case UNDERLYING_TYPE: + { + tree expr = tree_node (); + if (!get_overrun ()) + { + res = cxx_make_type (code); + TYPE_VALUES_RAW (res) = expr; + if (code == DECLTYPE_TYPE) + tree_node_bools (res); + SET_TYPE_STRUCTURAL_EQUALITY (res); + } + } + break; + + case TYPE_ARGUMENT_PACK: + if (!get_overrun ()) + { + tree pack = cxx_make_type (TYPE_ARGUMENT_PACK); + SET_ARGUMENT_PACK_ARGS (pack, res); + res = pack; + } + break; + + case TYPE_PACK_EXPANSION: + { + bool local = u (); + tree param_packs = tree_node (); + if (!get_overrun ()) + { + tree expn = cxx_make_type (TYPE_PACK_EXPANSION); + SET_TYPE_STRUCTURAL_EQUALITY (expn); + SET_PACK_EXPANSION_PATTERN (expn, res); + PACK_EXPANSION_PARAMETER_PACKS (expn) = param_packs; + PACK_EXPANSION_LOCAL_P (expn) = local; + res = expn; + } + } + break; + + case TYPENAME_TYPE: + { + tree ctx = tree_node (); + tree name = tree_node (); + tree fullname = tree_node (); + enum tag_types tag_type = tag_types (u ()); + + if (!get_overrun ()) + res = build_typename_type (ctx, name, fullname, tag_type); + } + break; + + case UNBOUND_CLASS_TEMPLATE: + { + tree ctx = tree_node (); + tree name = tree_node (); + tree parms = tree_node (); + + if (!get_overrun ()) + res = make_unbound_class_template_raw (ctx, name, parms); + } + break; + + case VECTOR_TYPE: + { + unsigned HOST_WIDE_INT nunits = wu (); + if (!get_overrun ()) + res = build_vector_type (res, static_cast<poly_int64> (nunits)); + } + break; + } + + int tag = i (); + if (!tag) + { + tag = insert (res); + if (res) + dump (dumper::TREE) + && dump ("Created:%d derived type %C", tag, code); + } + else + res = back_ref (tag); + } + break; + + case tt_variant_type: + /* Variant of some type. */ + { + res = tree_node (); + int flags = i (); + if (get_overrun ()) + ; + else if (flags < 0) + /* No change. */; + else if (TREE_CODE (res) == FUNCTION_TYPE + || TREE_CODE (res) == METHOD_TYPE) + { + cp_ref_qualifier rqual = cp_ref_qualifier (flags & 3); + bool late = (flags >> 2) & 1; + cp_cv_quals quals = cp_cv_quals (flags >> 3); + + tree raises = tree_node (); + if (raises == error_mark_node) + raises = TYPE_RAISES_EXCEPTIONS (res); + + res = build_cp_fntype_variant (res, rqual, raises, late); + if (TREE_CODE (res) == FUNCTION_TYPE) + res = apply_memfn_quals (res, quals, rqual); + } + else + { + res = build_aligned_type (res, 1u << flags); + TYPE_USER_ALIGN (res) = true; + } + + if (tree attribs = tree_node ()) + res = cp_build_type_attribute_variant (res, attribs); + + int quals = i (); + if (quals >= 0 && !get_overrun ()) + res = cp_build_qualified_type (res, quals); + + int tag = i (); + if (!tag) + { + tag = insert (res); + if (res) + dump (dumper::TREE) + && dump ("Created:%d variant type %C", tag, TREE_CODE (res)); + } + else + res = back_ref (tag); + } + break; + + case tt_tinfo_var: + case tt_tinfo_typedef: + /* A tinfo var or typedef. */ + { + bool is_var = tag == tt_tinfo_var; + unsigned ix = u (); + tree type = NULL_TREE; + + if (is_var) + { + tree name = tree_node (); + type = tree_node (); + + if (!get_overrun ()) + res = get_tinfo_decl_direct (type, name, int (ix)); + } + else + { + if (!get_overrun ()) + { + type = get_pseudo_tinfo_type (ix); + res = TYPE_NAME (type); + } + } + if (res) + { + int tag = insert (res); + dump (dumper::TREE) + && dump ("Created tinfo_%s:%d %S:%u for %N", + is_var ? "var" : "decl", tag, res, ix, type); + if (!is_var) + { + tag = insert (type); + dump (dumper::TREE) + && dump ("Created tinfo_type:%d %u %N", tag, ix, type); + } + } + } + break; + + case tt_ptrmem_type: + /* A pointer to member function. */ + { + tree type = tree_node (); + if (type && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE) + { + res = build_ptrmemfunc_type (type); + int tag = insert (res); + dump (dumper::TREE) && dump ("Created:%d ptrmem type", tag); + } + else + set_overrun (); + } + break; + + case tt_enum_value: + /* An enum const value. */ + { + if (tree decl = tree_node ()) + { + dump (dumper::TREE) && dump ("Read enum value %N", decl); + res = DECL_INITIAL (decl); + } + + if (!res) + set_overrun (); + } + break; + + case tt_enum_decl: + /* An enum decl. */ + { + tree ctx = tree_node (); + tree name = tree_node (); + + if (!get_overrun () + && TREE_CODE (ctx) == ENUMERAL_TYPE) + res = find_enum_member (ctx, name); + + if (!res) + set_overrun (); + else + { + int tag = insert (res); + dump (dumper::TREE) + && dump ("Read enum decl:%d %C:%N", tag, TREE_CODE (res), res); + } + } + break; + + case tt_data_member: + /* A data member. */ + { + tree ctx = tree_node (); + tree name = tree_node (); + + if (!get_overrun () + && RECORD_OR_UNION_TYPE_P (ctx)) + { + if (name) + res = lookup_class_binding (ctx, name); + else + res = lookup_field_ident (ctx, u ()); + + if (!res + || TREE_CODE (res) != FIELD_DECL + || DECL_CONTEXT (res) != ctx) + res = NULL_TREE; + } + + if (!res) + set_overrun (); + else + { + int tag = insert (res); + dump (dumper::TREE) + && dump ("Read member:%d %C:%N", tag, TREE_CODE (res), res); + } + } + break; + + case tt_binfo: + /* A BINFO. Walk the tree of the dominating type. */ + { + tree type; + unsigned ix = binfo_mergeable (&type); + if (type) + { + res = TYPE_BINFO (type); + for (; ix && res; res = TREE_CHAIN (res)) + ix--; + if (!res) + set_overrun (); + } + + if (get_overrun ()) + break; + + /* Insert binfo into backreferences. */ + tag = insert (res); + dump (dumper::TREE) && dump ("Read binfo:%d %N", tag, res); + } + break; + + case tt_vtable: + { + unsigned ix = u (); + tree ctx = tree_node (); + dump (dumper::TREE) && dump ("Reading vtable %N[%u]", ctx, ix); + if (TREE_CODE (ctx) == RECORD_TYPE && TYPE_LANG_SPECIFIC (ctx)) + for (res = CLASSTYPE_VTABLES (ctx); res; res = DECL_CHAIN (res)) + if (!ix--) + break; + if (!res) + set_overrun (); + } + break; + + case tt_thunk: + { + int fixed = i (); + tree target = tree_node (); + tree virt = tree_node (); + + for (tree thunk = DECL_THUNKS (target); + thunk; thunk = DECL_CHAIN (thunk)) + if (THUNK_FIXED_OFFSET (thunk) == fixed + && !THUNK_VIRTUAL_OFFSET (thunk) == !virt + && (!virt + || tree_int_cst_equal (virt, THUNK_VIRTUAL_OFFSET (thunk)))) + { + res = thunk; + break; + } + + int tag = insert (res); + if (res) + dump (dumper::TREE) + && dump ("Read:%d thunk %N to %N", tag, DECL_NAME (res), target); + else + set_overrun (); + } + break; + + case tt_clone_ref: + { + tree target = tree_node (); + tree name = tree_node (); + + if (DECL_P (target) && DECL_MAYBE_IN_CHARGE_CDTOR_P (target)) + { + tree clone; + FOR_EVERY_CLONE (clone, target) + if (DECL_NAME (clone) == name) + { + res = clone; + break; + } + } + + if (!res) + set_overrun (); + int tag = insert (res); + if (res) + dump (dumper::TREE) + && dump ("Read:%d clone %N of %N", tag, DECL_NAME (res), target); + else + set_overrun (); + } + break; + + case tt_entity: + /* Index into the entity table. Perhaps not loaded yet! */ + { + unsigned origin = state->slurp->remap_module (u ()); + unsigned ident = u (); + module_state *from = (*modules)[origin]; + + if (!origin || ident >= from->entity_num) + set_overrun (); + if (!get_overrun ()) + { + binding_slot *slot = &(*entity_ary)[from->entity_lwm + ident]; + if (slot->is_lazy ()) + if (!from->lazy_load (ident, slot)) + set_overrun (); + res = *slot; + } + + if (res) + { + const char *kind = (origin != state->mod ? "Imported" : "Named"); + int tag = insert (res); + dump (dumper::TREE) + && dump ("%s:%d %C:%N@%M", kind, tag, TREE_CODE (res), + res, (*modules)[origin]); + + if (!add_indirects (res)) + { + set_overrun (); + res = NULL_TREE; + } + } + } + break; + + case tt_template: + /* A template. */ + if (tree tpl = tree_node ()) + { + res = DECL_TEMPLATE_RESULT (tpl); + dump (dumper::TREE) + && dump ("Read template %C:%N", TREE_CODE (res), res); + } + break; + } + + if (is_use && !unused && res && DECL_P (res) && !TREE_USED (res)) + { + /* Mark decl used as mark_used does -- we cannot call + mark_used in the middle of streaming, we only need a subset + of its functionality. */ + TREE_USED (res) = true; + + /* And for structured bindings also the underlying decl. */ + if (DECL_DECOMPOSITION_P (res) && DECL_DECOMP_BASE (res)) + TREE_USED (DECL_DECOMP_BASE (res)) = true; + + if (DECL_CLONED_FUNCTION_P (res)) + TREE_USED (DECL_CLONED_FUNCTION (res)) = true; + } + + dump.outdent (); + return res; +} + +void +trees_out::tpl_parms (tree parms, unsigned &tpl_levels) +{ + if (!parms) + return; + + if (TREE_VISITED (parms)) + { + ref_node (parms); + return; + } + + tpl_parms (TREE_CHAIN (parms), tpl_levels); + + tree vec = TREE_VALUE (parms); + unsigned len = TREE_VEC_LENGTH (vec); + /* Depth. */ + int tag = insert (parms); + if (streaming_p ()) + { + i (len + 1); + dump (dumper::TREE) + && dump ("Writing template parms:%d level:%N length:%d", + tag, TREE_PURPOSE (parms), len); + } + tree_node (TREE_PURPOSE (parms)); + + for (unsigned ix = 0; ix != len; ix++) + { + tree parm = TREE_VEC_ELT (vec, ix); + tree decl = TREE_VALUE (parm); + + gcc_checking_assert (DECL_TEMPLATE_PARM_P (decl)); + if (CHECKING_P) + switch (TREE_CODE (decl)) + { + default: gcc_unreachable (); + + case TEMPLATE_DECL: + gcc_assert ((TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TEMPLATE_PARM) + && (TREE_CODE (DECL_TEMPLATE_RESULT (decl)) == TYPE_DECL) + && (TYPE_NAME (TREE_TYPE (decl)) == decl)); + break; + + case TYPE_DECL: + gcc_assert ((TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM) + && (TYPE_NAME (TREE_TYPE (decl)) == decl)); + break; + + case PARM_DECL: + gcc_assert ((TREE_CODE (DECL_INITIAL (decl)) == TEMPLATE_PARM_INDEX) + && (TREE_CODE (TEMPLATE_PARM_DECL (DECL_INITIAL (decl))) + == CONST_DECL) + && (DECL_TEMPLATE_PARM_P + (TEMPLATE_PARM_DECL (DECL_INITIAL (decl))))); + break; + } + + tree_node (decl); + tree_node (TEMPLATE_PARM_CONSTRAINTS (parm)); + } + + tpl_levels++; +} + +tree +trees_in::tpl_parms (unsigned &tpl_levels) +{ + tree parms = NULL_TREE; + + while (int len = i ()) + { + if (len < 0) + { + parms = back_ref (len); + continue; + } + + len -= 1; + parms = tree_cons (NULL_TREE, NULL_TREE, parms); + int tag = insert (parms); + TREE_PURPOSE (parms) = tree_node (); + + dump (dumper::TREE) + && dump ("Reading template parms:%d level:%N length:%d", + tag, TREE_PURPOSE (parms), len); + + tree vec = make_tree_vec (len); + for (int ix = 0; ix != len; ix++) + { + tree decl = tree_node (); + if (!decl) + return NULL_TREE; + + tree parm = build_tree_list (NULL, decl); + TEMPLATE_PARM_CONSTRAINTS (parm) = tree_node (); + + TREE_VEC_ELT (vec, ix) = parm; + } + + TREE_VALUE (parms) = vec; + tpl_levels++; + } + + return parms; +} + +void +trees_out::tpl_parms_fini (tree tmpl, unsigned tpl_levels) +{ + for (tree parms = DECL_TEMPLATE_PARMS (tmpl); + tpl_levels--; parms = TREE_CHAIN (parms)) + { + tree vec = TREE_VALUE (parms); + + tree_node (TREE_TYPE (vec)); + tree dflt = error_mark_node; + for (unsigned ix = TREE_VEC_LENGTH (vec); ix--;) + { + tree parm = TREE_VEC_ELT (vec, ix); + if (dflt) + { + dflt = TREE_PURPOSE (parm); + tree_node (dflt); + } + + if (streaming_p ()) + { + tree decl = TREE_VALUE (parm); + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree ctx = DECL_CONTEXT (decl); + tree inner = DECL_TEMPLATE_RESULT (decl); + tree tpi = (TREE_CODE (inner) == TYPE_DECL + ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl)) + : DECL_INITIAL (inner)); + bool original = (TEMPLATE_PARM_LEVEL (tpi) + == TEMPLATE_PARM_ORIG_LEVEL (tpi)); + /* Original template template parms have a context + of their owning template. Reduced ones do not. */ + gcc_checking_assert (original ? ctx == tmpl : !ctx); + } + } + } + } +} + +bool +trees_in::tpl_parms_fini (tree tmpl, unsigned tpl_levels) +{ + for (tree parms = DECL_TEMPLATE_PARMS (tmpl); + tpl_levels--; parms = TREE_CHAIN (parms)) + { + tree vec = TREE_VALUE (parms); + tree dflt = error_mark_node; + + TREE_TYPE (vec) = tree_node (); + for (unsigned ix = TREE_VEC_LENGTH (vec); ix--;) + { + tree parm = TREE_VEC_ELT (vec, ix); + if (dflt) + { + dflt = tree_node (); + if (get_overrun ()) + return false; + TREE_PURPOSE (parm) = dflt; + } + + tree decl = TREE_VALUE (parm); + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree inner = DECL_TEMPLATE_RESULT (decl); + tree tpi = (TREE_CODE (inner) == TYPE_DECL + ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl)) + : DECL_INITIAL (inner)); + bool original = (TEMPLATE_PARM_LEVEL (tpi) + == TEMPLATE_PARM_ORIG_LEVEL (tpi)); + /* Original template template parms have a context + of their owning template. Reduced ones do not. */ + if (original) + DECL_CONTEXT (decl) = tmpl; + } + } + } + return true; +} + +/* PARMS is a LIST, one node per level. + TREE_VALUE is a TREE_VEC of parm info for that level. + each ELT is a TREE_LIST + TREE_VALUE is PARM_DECL, TYPE_DECL or TEMPLATE_DECL + TREE_PURPOSE is the default value. */ + +void +trees_out::tpl_header (tree tpl, unsigned *tpl_levels) +{ + tree parms = DECL_TEMPLATE_PARMS (tpl); + tpl_parms (parms, *tpl_levels); + + /* Mark end. */ + if (streaming_p ()) + u (0); + + if (*tpl_levels) + tree_node (TEMPLATE_PARMS_CONSTRAINTS (parms)); +} + +bool +trees_in::tpl_header (tree tpl, unsigned *tpl_levels) +{ + tree parms = tpl_parms (*tpl_levels); + if (!parms) + return false; + + DECL_TEMPLATE_PARMS (tpl) = parms; + + if (*tpl_levels) + TEMPLATE_PARMS_CONSTRAINTS (parms) = tree_node (); + + return true; +} + +/* Stream skeleton parm nodes, with their flags, type & parm indices. + All the parms will have consecutive tags. */ + +void +trees_out::fn_parms_init (tree fn) +{ + /* First init them. */ + int base_tag = ref_num - 1; + int ix = 0; + for (tree parm = DECL_ARGUMENTS (fn); + parm; parm = DECL_CHAIN (parm), ix++) + { + if (streaming_p ()) + { + start (parm); + tree_node_bools (parm); + } + int tag = insert (parm); + gcc_checking_assert (base_tag - ix == tag); + } + /* Mark the end. */ + if (streaming_p ()) + u (0); + + /* Now stream their contents. */ + ix = 0; + for (tree parm = DECL_ARGUMENTS (fn); + parm; parm = DECL_CHAIN (parm), ix++) + { + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Writing parm:%d %u (%N) of %N", + base_tag - ix, ix, parm, fn); + tree_node_vals (parm); + } +} + +/* Build skeleton parm nodes, read their flags, type & parm indices. */ + +int +trees_in::fn_parms_init (tree fn) +{ + int base_tag = ~(int)back_refs.length (); + + tree *parm_ptr = &DECL_ARGUMENTS (fn); + int ix = 0; + for (; int code = u (); ix++) + { + tree parm = start (code); + if (!tree_node_bools (parm)) + return 0; + + int tag = insert (parm); + gcc_checking_assert (base_tag - ix == tag); + *parm_ptr = parm; + parm_ptr = &DECL_CHAIN (parm); + } + + ix = 0; + for (tree parm = DECL_ARGUMENTS (fn); + parm; parm = DECL_CHAIN (parm), ix++) + { + dump (dumper::TREE) + && dump ("Reading parm:%d %u (%N) of %N", + base_tag - ix, ix, parm, fn); + if (!tree_node_vals (parm)) + return 0; + } + + return base_tag; +} + +/* Read the remaining parm node data. Replace with existing (if + non-null) in the map. */ + +void +trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn) +{ + tree existing_parm = existing ? DECL_ARGUMENTS (existing) : NULL_TREE; + tree parms = DECL_ARGUMENTS (fn); + unsigned ix = 0; + for (tree parm = parms; parm; parm = DECL_CHAIN (parm), ix++) + { + if (existing_parm) + { + if (is_defn && !DECL_SAVED_TREE (existing)) + { + /* If we're about to become the definition, set the + names of the parms from us. */ + DECL_NAME (existing_parm) = DECL_NAME (parm); + DECL_SOURCE_LOCATION (existing_parm) = DECL_SOURCE_LOCATION (parm); + } + + back_refs[~tag] = existing_parm; + existing_parm = DECL_CHAIN (existing_parm); + } + tag--; + } +} + +/* DEP is the depset of some decl we're streaming by value. Determine + the merging behaviour. */ + +merge_kind +trees_out::get_merge_kind (tree decl, depset *dep) +{ + if (!dep) + { + if (VAR_OR_FUNCTION_DECL_P (decl)) + { + /* Any var or function with template info should have DEP. */ + gcc_checking_assert (!DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLATE_INFO (decl)); + if (DECL_LOCAL_DECL_P (decl)) + return MK_unique; + } + + /* Either unique, or some member of a class that cannot have an + out-of-class definition. For instance a FIELD_DECL. */ + tree ctx = CP_DECL_CONTEXT (decl); + if (TREE_CODE (ctx) == FUNCTION_DECL) + { + /* USING_DECLs cannot have DECL_TEMPLATE_INFO -- this isn't + permitting them to have one. */ + gcc_checking_assert (TREE_CODE (decl) == USING_DECL + || !DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLATE_INFO (decl)); + + return MK_unique; + } + + if (TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + return MK_local_friend; + + gcc_checking_assert (TYPE_P (ctx)); + if (TREE_CODE (decl) == USING_DECL) + return MK_field; + + if (TREE_CODE (decl) == FIELD_DECL) + { + if (DECL_NAME (decl)) + { + /* Anonymous FIELD_DECLs have a NULL name. */ + gcc_checking_assert (!IDENTIFIER_ANON_P (DECL_NAME (decl))); + return MK_named; + } + + if (!DECL_NAME (decl) + && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + && !DECL_BIT_FIELD_REPRESENTATIVE (decl)) + { + /* The underlying storage unit for a bitfield. We do not + need to dedup it, because it's only reachable through + the bitfields it represents. And those are deduped. */ + // FIXME: Is that assertion correct -- do we ever fish it + // out and put it in an expr? + gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + ? TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) + : TREE_CODE (TREE_TYPE (decl))) + == INTEGER_TYPE); + return MK_unique; + } + + return MK_field; + } + + if (TREE_CODE (decl) == CONST_DECL) + return MK_named; + + if (TREE_CODE (decl) == VAR_DECL + && DECL_VTABLE_OR_VTT_P (decl)) + return MK_vtable; + + if (DECL_THUNK_P (decl)) + /* Thunks are unique-enough, because they're only referenced + from the vtable. And that's either new (so we want the + thunks), or it's a duplicate (so it will be dropped). */ + return MK_unique; + + /* There should be no other cases. */ + gcc_unreachable (); + } + + gcc_checking_assert (TREE_CODE (decl) != FIELD_DECL + && TREE_CODE (decl) != USING_DECL + && TREE_CODE (decl) != CONST_DECL); + + if (is_key_order ()) + { + /* When doing the mergeablilty graph, there's an indirection to + the actual depset. */ + gcc_assert (dep->is_special ()); + dep = dep->deps[0]; + } + + gcc_checking_assert (decl == dep->get_entity ()); + + merge_kind mk = MK_named; + switch (dep->get_entity_kind ()) + { + default: + gcc_unreachable (); + + case depset::EK_PARTIAL: + mk = MK_partial; + break; + + case depset::EK_DECL: + { + tree ctx = CP_DECL_CONTEXT (decl); + + switch (TREE_CODE (ctx)) + { + default: + gcc_unreachable (); + + case FUNCTION_DECL: + // FIXME: This can occur for (a) voldemorty TYPE_DECLS + // (which are returned from a function), or (b) + // block-scope class definitions in template functions. + // These are as unique as the containing function. While + // on read-back we can discover if the CTX was a + // duplicate, we don't have a mechanism to get from the + // existing CTX to the existing version of this decl. + gcc_checking_assert + (DECL_IMPLICIT_TYPEDEF_P (STRIP_TEMPLATE (decl))); + + mk = MK_unique; + break; + + case RECORD_TYPE: + case UNION_TYPE: + if (DECL_NAME (decl) == as_base_identifier) + mk = MK_as_base; + else if (IDENTIFIER_ANON_P (DECL_NAME (decl))) + mk = MK_field; + break; + + case NAMESPACE_DECL: + if (DECL_IMPLICIT_TYPEDEF_P (STRIP_TEMPLATE (decl)) + && LAMBDA_TYPE_P (TREE_TYPE (decl))) + if (tree scope + = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR + (TREE_TYPE (decl)))) + if (TREE_CODE (scope) == VAR_DECL + && DECL_MODULE_ATTACHMENTS_P (scope)) + { + mk = MK_attached; + break; + } + + if (TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + mk = MK_local_friend; + else if (IDENTIFIER_ANON_P (DECL_NAME (decl))) + { + if (DECL_IMPLICIT_TYPEDEF_P (decl) + && UNSCOPED_ENUM_P (TREE_TYPE (decl)) + && TYPE_VALUES (TREE_TYPE (decl))) + /* Keyed by first enum value, and underlying type. */ + mk = MK_enum; + else + /* No way to merge it, it is an ODR land-mine. */ + mk = MK_unique; + } + } + } + break; + + case depset::EK_SPECIALIZATION: + { + gcc_checking_assert (dep->is_special ()); + spec_entry *entry = reinterpret_cast <spec_entry *> (dep->deps[0]); + + if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) + /* An block-scope classes of templates are themselves + templates. */ + gcc_checking_assert (DECL_IMPLICIT_TYPEDEF_P (decl)); + + if (dep->is_friend_spec ()) + mk = MK_friend_spec; + else if (dep->is_type_spec ()) + mk = MK_type_spec; + else if (dep->is_alias ()) + mk = MK_alias_spec; + else + mk = MK_decl_spec; + + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree res = DECL_TEMPLATE_RESULT (decl); + if (!(mk & MK_tmpl_decl_mask)) + res = TREE_TYPE (res); + + if (res == entry->spec) + /* We check we can get back to the template during + streaming. */ + mk = merge_kind (mk | MK_tmpl_tmpl_mask); + } + } + break; + } + + return mk; +} + + +/* The container of DECL -- not necessarily its context! */ + +tree +trees_out::decl_container (tree decl) +{ + int use_tpl; + tree tpl = NULL_TREE; + if (tree template_info = node_template_info (decl, use_tpl)) + tpl = TI_TEMPLATE (template_info); + if (tpl == decl) + tpl = nullptr; + + /* Stream the template we're instantiated from. */ + tree_node (tpl); + + tree container = NULL_TREE; + if (TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + container = DECL_CHAIN (decl); + else + container = CP_DECL_CONTEXT (decl); + + if (TYPE_P (container)) + container = TYPE_NAME (container); + + tree_node (container); + + return container; +} + +tree +trees_in::decl_container () +{ + /* The maybe-template. */ + (void)tree_node (); + + tree container = tree_node (); + + return container; +} + +/* Write out key information about a mergeable DEP. Does not write + the contents of DEP itself. The context has already been + written. The container has already been streamed. */ + +void +trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, + tree container, depset *dep) +{ + if (dep && is_key_order ()) + { + gcc_checking_assert (dep->is_special ()); + dep = dep->deps[0]; + } + + if (streaming_p ()) + dump (dumper::MERGE) + && dump ("Writing:%d's %s merge key (%s) %C:%N", tag, merge_kind_name[mk], + dep ? dep->entity_kind_name () : "contained", + TREE_CODE (decl), decl); + + /* Now write the locating information. */ + if (mk & MK_template_mask) + { + /* Specializations are located via their originating template, + and the set of template args they specialize. */ + gcc_checking_assert (dep && dep->is_special ()); + spec_entry *entry = reinterpret_cast <spec_entry *> (dep->deps[0]); + + tree_node (entry->tmpl); + tree_node (entry->args); + if (streaming_p ()) + u (get_mergeable_specialization_flags (entry->tmpl, decl)); + if (mk & MK_tmpl_decl_mask) + if (flag_concepts && TREE_CODE (inner) == VAR_DECL) + { + /* Variable template partial specializations might need + constraints (see spec_hasher::equal). It's simpler to + write NULL when we don't need them. */ + tree constraints = NULL_TREE; + + if (uses_template_parms (entry->args)) + constraints = get_constraints (inner); + tree_node (constraints); + } + + if (CHECKING_P) + { + /* Make sure we can locate the decl. */ + tree existing = match_mergeable_specialization + (bool (mk & MK_tmpl_decl_mask), entry, false); + + gcc_assert (existing); + if (mk & MK_tmpl_decl_mask) + { + if (mk & MK_tmpl_alias_mask) + /* It should be in both tables. */ + gcc_assert (match_mergeable_specialization (false, entry, false) + == TREE_TYPE (existing)); + else if (mk & MK_tmpl_tmpl_mask) + if (tree ti = DECL_TEMPLATE_INFO (existing)) + existing = TI_TEMPLATE (ti); + } + else + { + if (!(mk & MK_tmpl_tmpl_mask)) + existing = TYPE_NAME (existing); + else if (tree ti = CLASSTYPE_TEMPLATE_INFO (existing)) + existing = TI_TEMPLATE (ti); + } + + /* The walkabout should have found ourselves. */ + gcc_assert (existing == decl); + } + } + else if (mk != MK_unique) + { + merge_key key; + tree name = DECL_NAME (decl); + + switch (mk) + { + default: + gcc_unreachable (); + + case MK_named: + case MK_friend_spec: + if (IDENTIFIER_CONV_OP_P (name)) + name = conv_op_identifier; + + if (inner && TREE_CODE (inner) == FUNCTION_DECL) + { + /* Functions are distinguished by parameter types. */ + tree fn_type = TREE_TYPE (inner); + + key.ref_q = type_memfn_rqual (fn_type); + key.args = TYPE_ARG_TYPES (fn_type); + + if (tree reqs = get_constraints (inner)) + { + if (cxx_dialect < cxx20) + reqs = CI_ASSOCIATED_CONSTRAINTS (reqs); + else + reqs = CI_DECLARATOR_REQS (reqs); + key.constraints = reqs; + } + + if (IDENTIFIER_CONV_OP_P (name) + || (decl != inner + && !(name == fun_identifier + /* In case the user names something _FUN */ + && LAMBDA_TYPE_P (DECL_CONTEXT (inner))))) + /* And a function template, or conversion operator needs + the return type. Except for the _FUN thunk of a + generic lambda, which has a recursive decl_type'd + return type. */ + // FIXME: What if the return type is a voldemort? + key.ret = fndecl_declared_return_type (inner); + } + + if (mk == MK_friend_spec) + { + gcc_checking_assert (dep && dep->is_special ()); + spec_entry *entry = reinterpret_cast <spec_entry *> (dep->deps[0]); + + tree_node (entry->tmpl); + tree_node (entry->args); + if (streaming_p ()) + u (get_mergeable_specialization_flags (entry->tmpl, decl)); + } + break; + + case MK_field: + { + unsigned ix = 0; + if (TREE_CODE (inner) != FIELD_DECL) + name = NULL_TREE; + else + gcc_checking_assert (!name || !IDENTIFIER_ANON_P (name)); + + for (tree field = TYPE_FIELDS (TREE_TYPE (container)); + ; field = DECL_CHAIN (field)) + { + tree finner = STRIP_TEMPLATE (field); + if (TREE_CODE (finner) == TREE_CODE (inner)) + { + if (finner == inner) + break; + ix++; + } + } + key.index = ix; + } + break; + + case MK_vtable: + { + tree vtable = CLASSTYPE_VTABLES (TREE_TYPE (container)); + for (unsigned ix = 0; ; vtable = DECL_CHAIN (vtable), ix++) + if (vtable == decl) + { + key.index = ix; + break; + } + name = NULL_TREE; + } + break; + + case MK_as_base: + gcc_checking_assert + (decl == TYPE_NAME (CLASSTYPE_AS_BASE (TREE_TYPE (container)))); + break; + + case MK_local_friend: + { + /* Find by index on the class's DECL_LIST */ + unsigned ix = 0; + for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl)); + decls; decls = TREE_CHAIN (decls)) + if (!TREE_PURPOSE (decls)) + { + tree frnd = friend_from_decl_list (TREE_VALUE (decls)); + if (frnd == decl) + break; + ix++; + } + key.index = ix; + name = NULL_TREE; + } + break; + + case MK_enum: + { + /* Anonymous enums are located by their first identifier, + and underlying type. */ + tree type = TREE_TYPE (decl); + + gcc_checking_assert (UNSCOPED_ENUM_P (type)); + /* Using the type name drops the bit precision we might + have been using on the enum. */ + key.ret = TYPE_NAME (ENUM_UNDERLYING_TYPE (type)); + if (tree values = TYPE_VALUES (type)) + name = DECL_NAME (TREE_VALUE (values)); + } + break; + + case MK_attached: + { + gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (inner))); + tree scope = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR + (TREE_TYPE (inner))); + gcc_checking_assert (TREE_CODE (scope) == VAR_DECL); + attachset *root = attached_table->get (DECL_UID (scope)); + unsigned ix = root->num; + /* If we don't find it, we'll write a really big number + that the reader will ignore. */ + while (ix--) + if (root->values[ix] == inner) + break; + + /* Use the attached-to decl as the 'name'. */ + name = scope; + key.index = ix; + } + break; + + case MK_partial: + { + key.constraints = get_constraints (inner); + key.ret = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (inner)); + key.args = CLASSTYPE_TI_ARGS (TREE_TYPE (inner)); + } + break; + } + + tree_node (name); + if (streaming_p ()) + { + unsigned code = (key.ref_q << 0) | (key.index << 2); + u (code); + } + + if (mk == MK_enum) + tree_node (key.ret); + else if (mk == MK_partial + || (mk == MK_named && inner + && TREE_CODE (inner) == FUNCTION_DECL)) + { + tree_node (key.ret); + tree arg = key.args; + if (mk == MK_named) + while (arg && arg != void_list_node) + { + tree_node (TREE_VALUE (arg)); + arg = TREE_CHAIN (arg); + } + tree_node (arg); + tree_node (key.constraints); + } + } +} + +/* DECL is a new declaration that may be duplicated in OVL. Use RET & + ARGS to find its clone, or NULL. If DECL's DECL_NAME is NULL, this + has been found by a proxy. It will be an enum type located by it's + first member. + + We're conservative with matches, so ambiguous decls will be + registered as different, then lead to a lookup error if the two + modules are both visible. Perhaps we want to do something similar + to duplicate decls to get ODR errors on loading? We already have + some special casing for namespaces. */ + +static tree +check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) +{ + tree found = NULL_TREE; + for (ovl_iterator iter (ovl); !found && iter; ++iter) + { + tree match = *iter; + + tree d_inner = decl; + tree m_inner = match; + + again: + if (TREE_CODE (d_inner) != TREE_CODE (m_inner)) + { + if (TREE_CODE (match) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (match)) + /* Namespaces are never overloaded. */ + found = match; + + continue; + } + + switch (TREE_CODE (d_inner)) + { + case TEMPLATE_DECL: + if (template_heads_equivalent_p (d_inner, m_inner)) + { + d_inner = DECL_TEMPLATE_RESULT (d_inner); + m_inner = DECL_TEMPLATE_RESULT (m_inner); + if (d_inner == error_mark_node + && TYPE_DECL_ALIAS_P (m_inner)) + { + found = match; + break; + } + goto again; + } + break; + + case FUNCTION_DECL: + map_context_from = d_inner; + map_context_to = m_inner; + if (tree m_type = TREE_TYPE (m_inner)) + if ((!key.ret + || same_type_p (key.ret, fndecl_declared_return_type (m_inner))) + && type_memfn_rqual (m_type) == key.ref_q + && compparms (key.args, TYPE_ARG_TYPES (m_type)) + /* Reject if old is a "C" builtin and new is not "C". + Matches decls_match behaviour. */ + && (!DECL_IS_UNDECLARED_BUILTIN (m_inner) + || !DECL_EXTERN_C_P (m_inner) + || DECL_EXTERN_C_P (d_inner))) + { + tree m_reqs = get_constraints (m_inner); + if (m_reqs) + { + if (cxx_dialect < cxx20) + m_reqs = CI_ASSOCIATED_CONSTRAINTS (m_reqs); + else + m_reqs = CI_DECLARATOR_REQS (m_reqs); + } + + if (cp_tree_equal (key.constraints, m_reqs)) + found = match; + } + map_context_from = map_context_to = NULL_TREE; + break; + + case TYPE_DECL: + if (DECL_IMPLICIT_TYPEDEF_P (d_inner) + == DECL_IMPLICIT_TYPEDEF_P (m_inner)) + { + if (!IDENTIFIER_ANON_P (DECL_NAME (m_inner))) + return match; + else if (mk == MK_enum + && (TYPE_NAME (ENUM_UNDERLYING_TYPE (TREE_TYPE (m_inner))) + == key.ret)) + found = match; + } + break; + + default: + found = match; + break; + } + } + + return found; +} + +/* DECL, INNER & TYPE are a skeleton set of nodes for a decl. Only + the bools have been filled in. Read its merging key and merge it. + Returns the existing decl if there is one. */ + +tree +trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, + tree type, tree container, bool is_mod) +{ + const char *kind = "new"; + tree existing = NULL_TREE; + + if (mk & MK_template_mask) + { + spec_entry spec; + spec.tmpl = tree_node (); + spec.args = tree_node (); + unsigned flags = u (); + + DECL_NAME (decl) = DECL_NAME (spec.tmpl); + DECL_CONTEXT (decl) = DECL_CONTEXT (spec.tmpl); + DECL_NAME (inner) = DECL_NAME (decl); + DECL_CONTEXT (inner) = DECL_CONTEXT (decl); + + spec.spec = decl; + if (mk & MK_tmpl_tmpl_mask) + { + if (inner == decl) + return error_mark_node; + spec.spec = inner; + } + tree constr = NULL_TREE; + bool is_decl = mk & MK_tmpl_decl_mask; + if (is_decl) + { + if (flag_concepts && TREE_CODE (inner) == VAR_DECL) + { + constr = tree_node (); + if (constr) + set_constraints (inner, constr); + } + } + else + { + if (mk == MK_type_spec && inner != decl) + return error_mark_node; + spec.spec = type; + } + existing = match_mergeable_specialization (is_decl, &spec); + if (constr) + /* We'll add these back later, if this is the new decl. */ + remove_constraints (inner); + + if (!existing) + add_mergeable_specialization (spec.tmpl, spec.args, decl, flags); + else if (mk & MK_tmpl_decl_mask) + { + /* A declaration specialization. */ + if (mk & MK_tmpl_tmpl_mask) + if (tree ti = DECL_TEMPLATE_INFO (existing)) + { + tree tmpl = TI_TEMPLATE (ti); + if (DECL_TEMPLATE_RESULT (tmpl) == existing) + existing = tmpl; + } + } + else + { + /* A type specialization. */ + if (!(mk & MK_tmpl_tmpl_mask)) + existing = TYPE_NAME (existing); + else if (tree ti = CLASSTYPE_TEMPLATE_INFO (existing)) + { + tree tmpl = TI_TEMPLATE (ti); + if (DECL_TEMPLATE_RESULT (tmpl) == TYPE_NAME (existing)) + existing = tmpl; + } + } + } + else if (mk == MK_unique) + kind = "unique"; + else + { + tree name = tree_node (); + + merge_key key; + unsigned code = u (); + key.ref_q = cp_ref_qualifier ((code >> 0) & 3); + key.index = code >> 2; + + if (mk == MK_enum) + key.ret = tree_node (); + else if (mk == MK_partial + || ((mk == MK_named || mk == MK_friend_spec) + && inner && TREE_CODE (inner) == FUNCTION_DECL)) + { + key.ret = tree_node (); + tree arg, *arg_ptr = &key.args; + while ((arg = tree_node ()) + && arg != void_list_node + && mk != MK_partial) + { + *arg_ptr = tree_cons (NULL_TREE, arg, NULL_TREE); + arg_ptr = &TREE_CHAIN (*arg_ptr); + } + *arg_ptr = arg; + key.constraints = tree_node (); + } + + if (get_overrun ()) + return error_mark_node; + + if (mk < MK_indirect_lwm) + { + DECL_NAME (decl) = name; + DECL_CONTEXT (decl) = FROB_CONTEXT (container); + } + if (inner) + { + DECL_NAME (inner) = DECL_NAME (decl); + DECL_CONTEXT (inner) = DECL_CONTEXT (decl); + } + + if (mk == MK_partial) + { + for (tree spec = DECL_TEMPLATE_SPECIALIZATIONS (key.ret); + spec; spec = TREE_CHAIN (spec)) + { + tree tmpl = TREE_VALUE (spec); + if (template_args_equal (key.args, + CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))) + && cp_tree_equal (key.constraints, + get_constraints + (DECL_TEMPLATE_RESULT (tmpl)))) + { + existing = tmpl; + break; + } + } + if (!existing) + add_mergeable_specialization (key.ret, key.args, decl, 2); + } + else + switch (TREE_CODE (container)) + { + default: + gcc_unreachable (); + + case NAMESPACE_DECL: + if (mk == MK_attached) + { + if (DECL_LANG_SPECIFIC (name) + && VAR_OR_FUNCTION_DECL_P (name) + && DECL_MODULE_ATTACHMENTS_P (name)) + if (attachset *set = attached_table->get (DECL_UID (name))) + if (key.index < set->num) + { + existing = set->values[key.index]; + if (existing) + { + gcc_checking_assert + (DECL_IMPLICIT_TYPEDEF_P (existing)); + if (inner != decl) + existing + = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (existing)); + } + } + } + else if (is_mod && !(state->is_module () || state->is_partition ())) + kind = "unique"; + else + { + gcc_checking_assert (mk == MK_named || mk == MK_enum); + tree mvec; + tree *vslot = mergeable_namespace_slots (container, name, + !is_mod, &mvec); + existing = check_mergeable_decl (mk, decl, *vslot, key); + if (!existing) + add_mergeable_namespace_entity (vslot, decl); + else + { + /* Note that we now have duplicates to deal with in + name lookup. */ + if (is_mod) + BINDING_VECTOR_PARTITION_DUPS_P (mvec) = true; + else + BINDING_VECTOR_GLOBAL_DUPS_P (mvec) = true; + } + } + break; + + case FUNCTION_DECL: + // FIXME: What about a voldemort? how do we find what it + // duplicates? Do we have to number vmorts relative to + // their containing function? But how would that work + // when matching an in-TU declaration? + kind = "unique"; + break; + + case TYPE_DECL: + if (is_mod && !(state->is_module () || state->is_partition ()) + /* Implicit member functions can come from + anywhere. */ + && !(DECL_ARTIFICIAL (decl) + && TREE_CODE (decl) == FUNCTION_DECL + && !DECL_THUNK_P (decl))) + kind = "unique"; + else + { + tree ctx = TREE_TYPE (container); + + /* For some reason templated enumeral types are not marked + as COMPLETE_TYPE_P, even though they have members. + This may well be a bug elsewhere. */ + if (TREE_CODE (ctx) == ENUMERAL_TYPE) + existing = find_enum_member (ctx, name); + else if (COMPLETE_TYPE_P (ctx)) + { + switch (mk) + { + default: + gcc_unreachable (); + + case MK_named: + existing = lookup_class_binding (ctx, name); + if (existing) + { + tree inner = decl; + if (TREE_CODE (inner) == TEMPLATE_DECL + && !DECL_MEMBER_TEMPLATE_P (inner)) + inner = DECL_TEMPLATE_RESULT (inner); + + existing = check_mergeable_decl + (mk, inner, existing, key); + + if (!existing && DECL_ALIAS_TEMPLATE_P (decl)) + {} // FIXME: Insert into specialization + // tables, we'll need the arguments for that! + } + break; + + case MK_field: + { + unsigned ix = key.index; + for (tree field = TYPE_FIELDS (ctx); + field; field = DECL_CHAIN (field)) + { + tree finner = STRIP_TEMPLATE (field); + if (TREE_CODE (finner) == TREE_CODE (inner)) + if (!ix--) + { + existing = field; + break; + } + } + } + break; + + case MK_vtable: + { + unsigned ix = key.index; + for (tree vtable = CLASSTYPE_VTABLES (ctx); + vtable; vtable = DECL_CHAIN (vtable)) + if (!ix--) + { + existing = vtable; + break; + } + } + break; + + case MK_as_base: + { + tree as_base = CLASSTYPE_AS_BASE (ctx); + if (as_base && as_base != ctx) + existing = TYPE_NAME (as_base); + } + break; + + case MK_local_friend: + { + unsigned ix = key.index; + for (tree decls = CLASSTYPE_DECL_LIST (ctx); + decls; decls = TREE_CHAIN (decls)) + if (!TREE_PURPOSE (decls) && !ix--) + { + existing + = friend_from_decl_list (TREE_VALUE (decls)); + break; + } + } + break; + } + + if (existing && mk < MK_indirect_lwm && mk != MK_partial + && TREE_CODE (decl) == TEMPLATE_DECL + && !DECL_MEMBER_TEMPLATE_P (decl)) + { + tree ti; + if (DECL_IMPLICIT_TYPEDEF_P (existing)) + ti = TYPE_TEMPLATE_INFO (TREE_TYPE (existing)); + else + ti = DECL_TEMPLATE_INFO (existing); + existing = TI_TEMPLATE (ti); + } + } + } + } + + if (mk == MK_friend_spec) + { + spec_entry spec; + spec.tmpl = tree_node (); + spec.args = tree_node (); + spec.spec = decl; + unsigned flags = u (); + + tree e = match_mergeable_specialization (true, &spec); + if (!e) + add_mergeable_specialization (spec.tmpl, spec.args, + existing ? existing : decl, flags); + else if (e != existing) + set_overrun (); + } + } + + dump (dumper::MERGE) + && dump ("Read:%d's %s merge key (%s) %C:%N", tag, merge_kind_name[mk], + existing ? "matched" : kind, TREE_CODE (decl), decl); + + return existing; +} + +void +trees_out::binfo_mergeable (tree binfo) +{ + tree dom = binfo; + while (tree parent = BINFO_INHERITANCE_CHAIN (dom)) + dom = parent; + tree type = BINFO_TYPE (dom); + gcc_checking_assert (TYPE_BINFO (type) == dom); + tree_node (type); + if (streaming_p ()) + { + unsigned ix = 0; + for (; dom != binfo; dom = TREE_CHAIN (dom)) + ix++; + u (ix); + } +} + +unsigned +trees_in::binfo_mergeable (tree *type) +{ + *type = tree_node (); + return u (); +} + +/* DECL is a just streamed mergeable decl that should match EXISTING. Check + it does and issue an appropriate diagnostic if not. Merge any + bits from DECL to EXISTING. This is stricter matching than + decls_match, because we can rely on ODR-sameness, and we cannot use + decls_match because it can cause instantiations of constraints. */ + +bool +trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) +{ + // FIXME: We should probably do some duplicate decl-like stuff here + // (beware, default parms should be the same?) Can we just call + // duplicate_decls and teach it how to handle the module-specific + // permitted/required duplications? + + // We know at this point that the decls have matched by key, so we + // can elide some of the checking + gcc_checking_assert (TREE_CODE (existing) == TREE_CODE (decl)); + + tree d_inner = decl; + tree e_inner = existing; + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + d_inner = DECL_TEMPLATE_RESULT (d_inner); + e_inner = DECL_TEMPLATE_RESULT (e_inner); + gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner)); + } + + gcc_checking_assert (!map_context_from); + /* This mapping requres the new decl on the lhs and the existing + entity on the rhs of the comparitors below. */ + map_context_from = d_inner; + map_context_to = e_inner; + + if (TREE_CODE (d_inner) == FUNCTION_DECL) + { + tree e_ret = fndecl_declared_return_type (existing); + tree d_ret = fndecl_declared_return_type (decl); + + if (decl != d_inner && DECL_NAME (d_inner) == fun_identifier + && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner))) + /* This has a recursive type that will compare different. */; + else if (!same_type_p (d_ret, e_ret)) + goto mismatch; + + tree e_type = TREE_TYPE (e_inner); + tree d_type = TREE_TYPE (d_inner); + + if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) + goto mismatch; + + for (tree e_args = TYPE_ARG_TYPES (e_type), + d_args = TYPE_ARG_TYPES (d_type); + e_args != d_args && (e_args || d_args); + e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args)) + { + if (!(e_args && d_args)) + goto mismatch; + + if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args))) + goto mismatch; + + // FIXME: Check default values + } + + /* If EXISTING has an undeduced or uninstantiated exception + specification, but DECL does not, propagate the exception + specification. Otherwise we end up asserting or trying to + instantiate it in the middle of loading. */ + tree e_spec = TYPE_RAISES_EXCEPTIONS (e_type); + tree d_spec = TYPE_RAISES_EXCEPTIONS (d_type); + if (DEFERRED_NOEXCEPT_SPEC_P (e_spec)) + { + if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) + || (UNEVALUATED_NOEXCEPT_SPEC_P (e_spec) + && !UNEVALUATED_NOEXCEPT_SPEC_P (d_spec))) + { + dump (dumper::MERGE) + && dump ("Propagating instantiated noexcept to %N", existing); + TREE_TYPE (existing) = d_type; + + /* Propagate to existing clones. */ + tree clone; + FOR_EACH_CLONE (clone, existing) + { + if (TREE_TYPE (clone) == e_type) + TREE_TYPE (clone) = d_type; + else + TREE_TYPE (clone) + = build_exception_variant (TREE_TYPE (clone), d_spec); + } + } + } + else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) + && !comp_except_specs (d_spec, e_spec, ce_type)) + goto mismatch; + } + else if (is_typedef) + { + if (!DECL_ORIGINAL_TYPE (e_inner) + || !same_type_p (DECL_ORIGINAL_TYPE (d_inner), + DECL_ORIGINAL_TYPE (e_inner))) + goto mismatch; + } + /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs + here. I suspect the entities that directly do that are things + that shouldn't go to duplicate_decls (FIELD_DECLs etc). */ + else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) + { + mismatch: + map_context_from = map_context_to = NULL_TREE; + if (DECL_IS_UNDECLARED_BUILTIN (existing)) + /* Just like duplicate_decls, presum the user knows what + they're doing in overriding a builtin. */ + TREE_TYPE (existing) = TREE_TYPE (decl); + else + { + // FIXME:QOI Might be template specialization from a module, + // not necessarily global module + error_at (DECL_SOURCE_LOCATION (decl), + "conflicting global module declaration %#qD", decl); + inform (DECL_SOURCE_LOCATION (existing), + "existing declaration %#qD", existing); + return false; + } + } + + map_context_from = map_context_to = NULL_TREE; + + if (DECL_IS_UNDECLARED_BUILTIN (existing) + && !DECL_IS_UNDECLARED_BUILTIN (decl)) + { + /* We're matching a builtin that the user has yet to declare. + We are the one! This is very much duplicate-decl + shenanigans. */ + DECL_SOURCE_LOCATION (existing) = DECL_SOURCE_LOCATION (decl); + if (TREE_CODE (decl) != TYPE_DECL) + { + /* Propagate exceptions etc. */ + TREE_TYPE (existing) = TREE_TYPE (decl); + TREE_NOTHROW (existing) = TREE_NOTHROW (decl); + } + /* This is actually an import! */ + DECL_MODULE_IMPORT_P (existing) = true; + + /* Yay, sliced! */ + existing->base = decl->base; + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* Ew :( */ + memcpy (&existing->decl_common.size, + &decl->decl_common.size, + (offsetof (tree_decl_common, pt_uid) + - offsetof (tree_decl_common, size))); + auto bltin_class = DECL_BUILT_IN_CLASS (decl); + existing->function_decl.built_in_class = bltin_class; + auto fncode = DECL_UNCHECKED_FUNCTION_CODE (decl); + DECL_UNCHECKED_FUNCTION_CODE (existing) = fncode; + if (existing->function_decl.built_in_class == BUILT_IN_NORMAL) + { + if (builtin_decl_explicit_p (built_in_function (fncode))) + switch (fncode) + { + case BUILT_IN_STPCPY: + set_builtin_decl_implicit_p + (built_in_function (fncode), true); + break; + default: + set_builtin_decl_declared_p + (built_in_function (fncode), true); + break; + } + copy_attributes_to_builtin (decl); + } + } + } + + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_TEMPLATE_INSTANTIATED (decl)) + /* Don't instantiate again! */ + DECL_TEMPLATE_INSTANTIATED (existing) = true; + + if (TREE_CODE (d_inner) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (d_inner)) + DECL_DECLARED_INLINE_P (e_inner) = true; + if (!DECL_EXTERNAL (d_inner)) + DECL_EXTERNAL (e_inner) = false; + + // FIXME: Check default tmpl and fn parms here + + return true; +} + +/* FN is an implicit member function that we've discovered is new to + the class. Add it to the TYPE_FIELDS chain and the method vector. + Reset the appropriate classtype lazy flag. */ + +bool +trees_in::install_implicit_member (tree fn) +{ + tree ctx = DECL_CONTEXT (fn); + tree name = DECL_NAME (fn); + /* We know these are synthesized, so the set of expected prototypes + is quite restricted. We're not validating correctness, just + distinguishing beteeen the small set of possibilities. */ + tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (fn)); + if (IDENTIFIER_CTOR_P (name)) + { + if (CLASSTYPE_LAZY_DEFAULT_CTOR (ctx) + && VOID_TYPE_P (parm_type)) + CLASSTYPE_LAZY_DEFAULT_CTOR (ctx) = false; + else if (!TYPE_REF_P (parm_type)) + return false; + else if (CLASSTYPE_LAZY_COPY_CTOR (ctx) + && !TYPE_REF_IS_RVALUE (parm_type)) + CLASSTYPE_LAZY_COPY_CTOR (ctx) = false; + else if (CLASSTYPE_LAZY_MOVE_CTOR (ctx)) + CLASSTYPE_LAZY_MOVE_CTOR (ctx) = false; + else + return false; + } + else if (IDENTIFIER_DTOR_P (name)) + { + if (CLASSTYPE_LAZY_DESTRUCTOR (ctx)) + CLASSTYPE_LAZY_DESTRUCTOR (ctx) = false; + else + return false; + if (DECL_VIRTUAL_P (fn)) + /* A virtual dtor should have been created when the class + became complete. */ + return false; + } + else if (name == assign_op_identifier) + { + if (!TYPE_REF_P (parm_type)) + return false; + else if (CLASSTYPE_LAZY_COPY_ASSIGN (ctx) + && !TYPE_REF_IS_RVALUE (parm_type)) + CLASSTYPE_LAZY_COPY_ASSIGN (ctx) = false; + else if (CLASSTYPE_LAZY_MOVE_ASSIGN (ctx)) + CLASSTYPE_LAZY_MOVE_ASSIGN (ctx) = false; + else + return false; + } + else + return false; + + dump (dumper::MERGE) && dump ("Adding implicit member %N", fn); + + DECL_CHAIN (fn) = TYPE_FIELDS (ctx); + TYPE_FIELDS (ctx) = fn; + + add_method (ctx, fn, false); + + /* Propagate TYPE_FIELDS. */ + fixup_type_variants (ctx); + + return true; +} + +/* Return non-zero if DECL has a definition that would be interesting to + write out. */ + +static bool +has_definition (tree decl) +{ + bool is_tmpl = TREE_CODE (decl) == TEMPLATE_DECL; + if (is_tmpl) + decl = DECL_TEMPLATE_RESULT (decl); + + switch (TREE_CODE (decl)) + { + default: + break; + + case FUNCTION_DECL: + if (!DECL_SAVED_TREE (decl)) + /* Not defined. */ + break; + + if (DECL_DECLARED_INLINE_P (decl)) + return true; + + if (DECL_THIS_STATIC (decl) + && (header_module_p () + || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl)))) + /* GM static function. */ + return true; + + if (DECL_TEMPLATE_INFO (decl)) + { + int use_tpl = DECL_USE_TEMPLATE (decl); + + // FIXME: Partial specializations have definitions too. + if (use_tpl < 2) + return true; + } + break; + + case TYPE_DECL: + { + tree type = TREE_TYPE (decl); + if (type == TYPE_MAIN_VARIANT (type) + && decl == TYPE_NAME (type) + && (TREE_CODE (type) == ENUMERAL_TYPE + ? TYPE_VALUES (type) : TYPE_FIELDS (type))) + return true; + } + break; + + case VAR_DECL: + if (DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && DECL_USE_TEMPLATE (decl) < 2) + return DECL_INITIAL (decl); + else + { + if (!DECL_INITIALIZED_P (decl)) + return false; + + if (header_module_p () + || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl))) + /* GM static variable. */ + return true; + + if (!TREE_CONSTANT (decl)) + return false; + + return true; + } + break; + + case CONCEPT_DECL: + if (DECL_INITIAL (decl)) + return true; + + break; + } + + return false; +} + +uintptr_t * +trees_in::find_duplicate (tree existing) +{ + if (!duplicates) + return NULL; + + return duplicates->get (existing); +} + +/* We're starting to read a duplicate DECL. EXISTING is the already + known node. */ + +void +trees_in::register_duplicate (tree decl, tree existing) +{ + if (!duplicates) + duplicates = new duplicate_hash_map (40); + + bool existed; + uintptr_t &slot = duplicates->get_or_insert (existing, &existed); + gcc_checking_assert (!existed); + slot = reinterpret_cast<uintptr_t> (decl); +} + +/* We've read a definition of MAYBE_EXISTING. If not a duplicate, + return MAYBE_EXISTING (into which the definition should be + installed). Otherwise return NULL if already known bad, or the + duplicate we read (for ODR checking, or extracting addtional merge + information). */ + +tree +trees_in::odr_duplicate (tree maybe_existing, bool has_defn) +{ + tree res = NULL_TREE; + + if (uintptr_t *dup = find_duplicate (maybe_existing)) + { + if (!(*dup & 1)) + res = reinterpret_cast<tree> (*dup); + } + else + res = maybe_existing; + + assert_definition (maybe_existing, res && !has_defn); + + // FIXME: We probably need to return the template, so that the + // template header can be checked? + return res ? STRIP_TEMPLATE (res) : NULL_TREE; +} + +/* The following writer functions rely on the current behaviour of + depset::hash::add_dependency making the decl and defn depset nodes + depend on eachother. That way we don't have to worry about seeding + the tree map with named decls that cannot be looked up by name (I.e + template and function parms). We know the decl and definition will + be in the same cluster, which is what we want. */ + +void +trees_out::write_function_def (tree decl) +{ + tree_node (DECL_RESULT (decl)); + tree_node (DECL_INITIAL (decl)); + tree_node (DECL_SAVED_TREE (decl)); + tree_node (DECL_FRIEND_CONTEXT (decl)); + + constexpr_fundef *cexpr = retrieve_constexpr_fundef (decl); + int tag = 0; + if (cexpr) + { + if (cexpr->result == error_mark_node) + /* We'll stream the RESULT_DECL naturally during the + serialization. We never need to fish it back again, so + that's ok. */ + tag = 0; + else + tag = insert (cexpr->result); + } + if (streaming_p ()) + { + i (tag); + if (tag) + dump (dumper::TREE) + && dump ("Constexpr:%d result %N", tag, cexpr->result); + } + if (tag) + { + unsigned ix = 0; + for (tree parm = cexpr->parms; parm; parm = DECL_CHAIN (parm), ix++) + { + tag = insert (parm); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Constexpr:%d parm:%u %N", tag, ix, parm); + } + tree_node (cexpr->body); + } + + if (streaming_p ()) + { + unsigned flags = 0; + + if (DECL_NOT_REALLY_EXTERN (decl)) + flags |= 1; + + u (flags); + } +} + +void +trees_out::mark_function_def (tree) +{ +} + +bool +trees_in::read_function_def (tree decl, tree maybe_template) +{ + dump () && dump ("Reading function definition %N", decl); + tree result = tree_node (); + tree initial = tree_node (); + tree saved = tree_node (); + tree context = tree_node (); + constexpr_fundef cexpr; + + tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl)); + bool installing = maybe_dup && !DECL_SAVED_TREE (decl); + + if (maybe_dup) + for (auto parm = DECL_ARGUMENTS (maybe_dup); parm; parm = DECL_CHAIN (parm)) + DECL_CONTEXT (parm) = decl; + + if (int wtag = i ()) + { + int tag = 1; + cexpr.result = error_mark_node; + + cexpr.result = copy_decl (result); + tag = insert (cexpr.result); + + if (wtag != tag) + set_overrun (); + dump (dumper::TREE) + && dump ("Constexpr:%d result %N", tag, cexpr.result); + + cexpr.parms = NULL_TREE; + tree *chain = &cexpr.parms; + unsigned ix = 0; + for (tree parm = DECL_ARGUMENTS (maybe_dup ? maybe_dup : decl); + parm; parm = DECL_CHAIN (parm), ix++) + { + tree p = copy_decl (parm); + tag = insert (p); + dump (dumper::TREE) + && dump ("Constexpr:%d parm:%u %N", tag, ix, p); + *chain = p; + chain = &DECL_CHAIN (p); + } + cexpr.body = tree_node (); + cexpr.decl = decl; + } + else + cexpr.decl = NULL_TREE; + + unsigned flags = u (); + + if (get_overrun ()) + return NULL_TREE; + + if (installing) + { + DECL_NOT_REALLY_EXTERN (decl) = flags & 1; + DECL_RESULT (decl) = result; + DECL_INITIAL (decl) = initial; + DECL_SAVED_TREE (decl) = saved; + if (maybe_dup) + DECL_ARGUMENTS (decl) = DECL_ARGUMENTS (maybe_dup); + + if (context) + SET_DECL_FRIEND_CONTEXT (decl, context); + if (cexpr.decl) + register_constexpr_fundef (cexpr); + post_process (maybe_template); + } + else if (maybe_dup) + { + // FIXME:QOI Check matching defn + } + + return true; +} + +/* Also for CONCEPT_DECLs. */ + +void +trees_out::write_var_def (tree decl) +{ + tree init = DECL_INITIAL (decl); + tree_node (init); + if (!init) + { + tree dyn_init = NULL_TREE; + + if (DECL_NONTRIVIALLY_INITIALIZED_P (decl)) + { + dyn_init = value_member (decl, + CP_DECL_THREAD_LOCAL_P (decl) + ? tls_aggregates : static_aggregates); + gcc_checking_assert (dyn_init); + /* Mark it so write_inits knows this is needed. */ + TREE_LANG_FLAG_0 (dyn_init) = true; + dyn_init = TREE_PURPOSE (dyn_init); + } + tree_node (dyn_init); + } +} + +void +trees_out::mark_var_def (tree) +{ +} + +bool +trees_in::read_var_def (tree decl, tree maybe_template) +{ + /* Do not mark the virtual table entries as used. */ + bool vtable = TREE_CODE (decl) == VAR_DECL && DECL_VTABLE_OR_VTT_P (decl); + unused += vtable; + tree init = tree_node (); + tree dyn_init = init ? NULL_TREE : tree_node (); + unused -= vtable; + + if (get_overrun ()) + return false; + + bool initialized = (VAR_P (decl) ? bool (DECL_INITIALIZED_P (decl)) + : bool (DECL_INITIAL (decl))); + tree maybe_dup = odr_duplicate (maybe_template, initialized); + bool installing = maybe_dup && !initialized; + if (installing) + { + if (DECL_EXTERNAL (decl)) + DECL_NOT_REALLY_EXTERN (decl) = true; + if (VAR_P (decl)) + DECL_INITIALIZED_P (decl) = true; + DECL_INITIAL (decl) = init; + if (!dyn_init) + ; + else if (CP_DECL_THREAD_LOCAL_P (decl)) + tls_aggregates = tree_cons (dyn_init, decl, tls_aggregates); + else + static_aggregates = tree_cons (dyn_init, decl, static_aggregates); + } + else if (maybe_dup) + { + // FIXME:QOI Check matching defn + } + + return true; +} + +/* If MEMBER doesn't have an independent life outside the class, + return it (or it's TEMPLATE_DECL). Otherwise NULL. */ + +static tree +member_owned_by_class (tree member) +{ + gcc_assert (DECL_P (member)); + + /* Clones are owned by their origin. */ + if (DECL_CLONED_FUNCTION_P (member)) + return NULL; + + if (TREE_CODE (member) == FIELD_DECL) + /* FIELD_DECLS can have template info in some cases. We always + want the FIELD_DECL though, as there's never a TEMPLATE_DECL + wrapping them. */ + return member; + + int use_tpl = -1; + if (tree ti = node_template_info (member, use_tpl)) + { + // FIXME: Don't bail on things that CANNOT have their own + // template header. No, make sure they're in the same cluster. + if (use_tpl > 0) + return NULL_TREE; + + if (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == member) + member = TI_TEMPLATE (ti); + } + return member; +} + +void +trees_out::write_class_def (tree defn) +{ + gcc_assert (DECL_P (defn)); + if (streaming_p ()) + dump () && dump ("Writing class definition %N", defn); + + tree type = TREE_TYPE (defn); + tree_node (TYPE_SIZE (type)); + tree_node (TYPE_SIZE_UNIT (type)); + tree_node (TYPE_VFIELD (type)); + tree_node (TYPE_BINFO (type)); + + vec_chained_decls (TYPE_FIELDS (type)); + + /* Every class but __as_base has a type-specific. */ + gcc_checking_assert (!TYPE_LANG_SPECIFIC (type) == IS_FAKE_BASE_TYPE (type)); + + if (TYPE_LANG_SPECIFIC (type)) + { + { + vec<tree, va_gc> *v = CLASSTYPE_MEMBER_VEC (type); + if (!v) + { + gcc_checking_assert (!streaming_p ()); + /* Force a class vector. */ + v = set_class_bindings (type, -1); + gcc_checking_assert (v); + } + + unsigned len = v->length (); + if (streaming_p ()) + u (len); + for (unsigned ix = 0; ix != len; ix++) + { + tree m = (*v)[ix]; + if (TREE_CODE (m) == TYPE_DECL + && DECL_ARTIFICIAL (m) + && TYPE_STUB_DECL (TREE_TYPE (m)) == m) + /* This is a using-decl for a type, or an anonymous + struct (maybe with a typedef name). Write the type. */ + m = TREE_TYPE (m); + tree_node (m); + } + } + tree_node (CLASSTYPE_LAMBDA_EXPR (type)); + + /* TYPE_CONTAINS_VPTR_P looks at the vbase vector, which the + reader won't know at this point. */ + int has_vptr = TYPE_CONTAINS_VPTR_P (type); + + if (streaming_p ()) + { + unsigned nvbases = vec_safe_length (CLASSTYPE_VBASECLASSES (type)); + u (nvbases); + i (has_vptr); + } + + if (has_vptr) + { + tree_vec (CLASSTYPE_PURE_VIRTUALS (type)); + tree_pair_vec (CLASSTYPE_VCALL_INDICES (type)); + tree_node (CLASSTYPE_KEY_METHOD (type)); + } + } + + if (TYPE_LANG_SPECIFIC (type)) + { + tree_node (CLASSTYPE_PRIMARY_BINFO (type)); + + tree as_base = CLASSTYPE_AS_BASE (type); + if (as_base) + as_base = TYPE_NAME (as_base); + tree_node (as_base); + + /* Write the vtables. */ + tree vtables = CLASSTYPE_VTABLES (type); + vec_chained_decls (vtables); + for (; vtables; vtables = TREE_CHAIN (vtables)) + write_definition (vtables); + + /* Write the friend classes. */ + tree_list (CLASSTYPE_FRIEND_CLASSES (type), false); + + /* Write the friend functions. */ + for (tree friends = DECL_FRIENDLIST (defn); + friends; friends = TREE_CHAIN (friends)) + { + /* Name of these friends. */ + tree_node (TREE_PURPOSE (friends)); + tree_list (TREE_VALUE (friends), false); + } + /* End of friend fns. */ + tree_node (NULL_TREE); + + /* Write the decl list. */ + tree_list (CLASSTYPE_DECL_LIST (type), true); + + if (TYPE_CONTAINS_VPTR_P (type)) + { + /* Write the thunks. */ + for (tree decls = TYPE_FIELDS (type); + decls; decls = DECL_CHAIN (decls)) + if (TREE_CODE (decls) == FUNCTION_DECL + && DECL_VIRTUAL_P (decls) + && DECL_THUNKS (decls)) + { + tree_node (decls); + /* Thunks are always unique, so chaining is ok. */ + chained_decls (DECL_THUNKS (decls)); + } + tree_node (NULL_TREE); + } + } +} + +void +trees_out::mark_class_member (tree member, bool do_defn) +{ + gcc_assert (DECL_P (member)); + + member = member_owned_by_class (member); + if (member) + mark_declaration (member, do_defn && has_definition (member)); +} + +void +trees_out::mark_class_def (tree defn) +{ + gcc_assert (DECL_P (defn)); + tree type = TREE_TYPE (defn); + /* Mark the class members that are not type-decls and cannot have + independent definitions. */ + for (tree member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member)) + if (TREE_CODE (member) == FIELD_DECL + || TREE_CODE (member) == USING_DECL + /* A cloned enum-decl from 'using enum unrelated;' */ + || (TREE_CODE (member) == CONST_DECL + && DECL_CONTEXT (member) == type)) + { + mark_class_member (member); + if (TREE_CODE (member) == FIELD_DECL) + if (tree repr = DECL_BIT_FIELD_REPRESENTATIVE (member)) + mark_declaration (repr, false); + } + + /* Mark the binfo hierarchy. */ + for (tree child = TYPE_BINFO (type); child; child = TREE_CHAIN (child)) + mark_by_value (child); + + if (TYPE_LANG_SPECIFIC (type)) + { + for (tree vtable = CLASSTYPE_VTABLES (type); + vtable; vtable = TREE_CHAIN (vtable)) + mark_declaration (vtable, true); + + if (TYPE_CONTAINS_VPTR_P (type)) + /* Mark the thunks, they belong to the class definition, + /not/ the thunked-to function. */ + for (tree decls = TYPE_FIELDS (type); + decls; decls = DECL_CHAIN (decls)) + if (TREE_CODE (decls) == FUNCTION_DECL) + for (tree thunks = DECL_THUNKS (decls); + thunks; thunks = DECL_CHAIN (thunks)) + mark_declaration (thunks, false); + } +} + +/* Nop sorting, needed for resorting the member vec. */ + +static void +nop (void *, void *) +{ +} + +bool +trees_in::read_class_def (tree defn, tree maybe_template) +{ + gcc_assert (DECL_P (defn)); + dump () && dump ("Reading class definition %N", defn); + tree type = TREE_TYPE (defn); + tree size = tree_node (); + tree size_unit = tree_node (); + tree vfield = tree_node (); + tree binfo = tree_node (); + vec<tree, va_gc> *vbase_vec = NULL; + vec<tree, va_gc> *member_vec = NULL; + vec<tree, va_gc> *pure_virts = NULL; + vec<tree_pair_s, va_gc> *vcall_indices = NULL; + tree key_method = NULL_TREE; + tree lambda = NULL_TREE; + + /* Read the fields. */ + vec<tree, va_heap> *fields = vec_chained_decls (); + + if (TYPE_LANG_SPECIFIC (type)) + { + if (unsigned len = u ()) + { + vec_alloc (member_vec, len); + for (unsigned ix = 0; ix != len; ix++) + { + tree m = tree_node (); + if (get_overrun ()) + break; + if (TYPE_P (m)) + m = TYPE_STUB_DECL (m); + member_vec->quick_push (m); + } + } + lambda = tree_node (); + + if (!get_overrun ()) + { + unsigned nvbases = u (); + if (nvbases) + { + vec_alloc (vbase_vec, nvbases); + for (tree child = binfo; child; child = TREE_CHAIN (child)) + if (BINFO_VIRTUAL_P (child)) + vbase_vec->quick_push (child); + } + } + + if (!get_overrun ()) + { + int has_vptr = i (); + if (has_vptr) + { + pure_virts = tree_vec (); + vcall_indices = tree_pair_vec (); + key_method = tree_node (); + } + } + } + + tree maybe_dup = odr_duplicate (maybe_template, TYPE_SIZE (type)); + bool installing = maybe_dup && !TYPE_SIZE (type); + if (installing) + { + if (DECL_EXTERNAL (defn) && TYPE_LANG_SPECIFIC (type)) + { + /* We don't deal with not-really-extern, because, for a + module you want the import to be the interface, and for a + header-unit, you're doing it wrong. */ + CLASSTYPE_INTERFACE_UNKNOWN (type) = false; + CLASSTYPE_INTERFACE_ONLY (type) = true; + } + + if (maybe_dup != defn) + { + // FIXME: This is needed on other defns too, almost + // duplicate-decl like? See is_matching_decl too. + /* Copy flags from the duplicate. */ + tree type_dup = TREE_TYPE (maybe_dup); + + /* Core pieces. */ + TYPE_MODE_RAW (type) = TYPE_MODE_RAW (type_dup); + SET_DECL_MODE (defn, DECL_MODE (maybe_dup)); + TREE_ADDRESSABLE (type) = TREE_ADDRESSABLE (type_dup); + DECL_SIZE (defn) = DECL_SIZE (maybe_dup); + DECL_SIZE_UNIT (defn) = DECL_SIZE_UNIT (maybe_dup); + DECL_ALIGN_RAW (defn) = DECL_ALIGN_RAW (maybe_dup); + DECL_WARN_IF_NOT_ALIGN_RAW (defn) + = DECL_WARN_IF_NOT_ALIGN_RAW (maybe_dup); + DECL_USER_ALIGN (defn) = DECL_USER_ALIGN (maybe_dup); + + /* C++ pieces. */ + TYPE_POLYMORPHIC_P (type) = TYPE_POLYMORPHIC_P (type_dup); + TYPE_HAS_USER_CONSTRUCTOR (type) + = TYPE_HAS_USER_CONSTRUCTOR (type_dup); + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type_dup); + + if (auto ls = TYPE_LANG_SPECIFIC (type_dup)) + { + if (TYPE_LANG_SPECIFIC (type)) + { + CLASSTYPE_BEFRIENDING_CLASSES (type_dup) + = CLASSTYPE_BEFRIENDING_CLASSES (type); + CLASSTYPE_TYPEINFO_VAR (type_dup) + = CLASSTYPE_TYPEINFO_VAR (type); + } + for (tree v = type; v; v = TYPE_NEXT_VARIANT (v)) + TYPE_LANG_SPECIFIC (v) = ls; + } + } + + TYPE_SIZE (type) = size; + TYPE_SIZE_UNIT (type) = size_unit; + + if (fields) + { + tree *chain = &TYPE_FIELDS (type); + unsigned len = fields->length (); + for (unsigned ix = 0; ix != len; ix++) + { + tree decl = (*fields)[ix]; + + if (!decl) + { + /* An anonymous struct with typedef name. */ + tree tdef = (*fields)[ix+1]; + decl = TYPE_STUB_DECL (TREE_TYPE (tdef)); + gcc_checking_assert (IDENTIFIER_ANON_P (DECL_NAME (decl)) + && decl != tdef); + } + + gcc_checking_assert (!*chain == !DECL_CLONED_FUNCTION_P (decl)); + *chain = decl; + chain = &DECL_CHAIN (decl); + + if (TREE_CODE (decl) == USING_DECL + && TREE_CODE (USING_DECL_SCOPE (decl)) == RECORD_TYPE) + { + /* Reconstruct DECL_ACCESS. */ + tree decls = USING_DECL_DECLS (decl); + tree access = declared_access (decl); + + for (ovl_iterator iter (decls); iter; ++iter) + { + tree d = *iter; + + retrofit_lang_decl (d); + tree list = DECL_ACCESS (d); + + if (!purpose_member (type, list)) + DECL_ACCESS (d) = tree_cons (type, access, list); + } + } + } + } + + TYPE_VFIELD (type) = vfield; + TYPE_BINFO (type) = binfo; + + if (TYPE_LANG_SPECIFIC (type)) + { + CLASSTYPE_LAMBDA_EXPR (type) = lambda; + + CLASSTYPE_MEMBER_VEC (type) = member_vec; + CLASSTYPE_PURE_VIRTUALS (type) = pure_virts; + CLASSTYPE_VCALL_INDICES (type) = vcall_indices; + + CLASSTYPE_KEY_METHOD (type) = key_method; + + CLASSTYPE_VBASECLASSES (type) = vbase_vec; + + /* Resort the member vector. */ + resort_type_member_vec (member_vec, NULL, nop, NULL); + } + } + else if (maybe_dup) + { + // FIXME:QOI Check matching defn + } + + if (TYPE_LANG_SPECIFIC (type)) + { + tree primary = tree_node (); + tree as_base = tree_node (); + + if (as_base) + as_base = TREE_TYPE (as_base); + + /* Read the vtables. */ + vec<tree, va_heap> *vtables = vec_chained_decls (); + if (vtables) + { + unsigned len = vtables->length (); + for (unsigned ix = 0; ix != len; ix++) + { + tree vtable = (*vtables)[ix]; + read_var_def (vtable, vtable); + } + } + + tree friend_classes = tree_list (false); + tree friend_functions = NULL_TREE; + for (tree *chain = &friend_functions; + tree name = tree_node (); chain = &TREE_CHAIN (*chain)) + { + tree val = tree_list (false); + *chain = build_tree_list (name, val); + } + tree decl_list = tree_list (true); + + if (installing) + { + CLASSTYPE_PRIMARY_BINFO (type) = primary; + CLASSTYPE_AS_BASE (type) = as_base; + + if (vtables) + { + if (!CLASSTYPE_KEY_METHOD (type) + /* Sneaky user may have defined it inline + out-of-class. */ + || DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (type))) + vec_safe_push (keyed_classes, type); + unsigned len = vtables->length (); + tree *chain = &CLASSTYPE_VTABLES (type); + for (unsigned ix = 0; ix != len; ix++) + { + tree vtable = (*vtables)[ix]; + gcc_checking_assert (!*chain); + *chain = vtable; + chain = &DECL_CHAIN (vtable); + } + } + CLASSTYPE_FRIEND_CLASSES (type) = friend_classes; + DECL_FRIENDLIST (defn) = friend_functions; + CLASSTYPE_DECL_LIST (type) = decl_list; + + for (; friend_classes; friend_classes = TREE_CHAIN (friend_classes)) + { + tree f = TREE_VALUE (friend_classes); + + if (TYPE_P (f)) + { + CLASSTYPE_BEFRIENDING_CLASSES (f) + = tree_cons (NULL_TREE, type, + CLASSTYPE_BEFRIENDING_CLASSES (f)); + dump () && dump ("Class %N befriending %C:%N", + type, TREE_CODE (f), f); + } + } + + for (; friend_functions; + friend_functions = TREE_CHAIN (friend_functions)) + for (tree friend_decls = TREE_VALUE (friend_functions); + friend_decls; friend_decls = TREE_CHAIN (friend_decls)) + { + tree f = TREE_VALUE (friend_decls); + + DECL_BEFRIENDING_CLASSES (f) + = tree_cons (NULL_TREE, type, DECL_BEFRIENDING_CLASSES (f)); + dump () && dump ("Class %N befriending %C:%N", + type, TREE_CODE (f), f); + } + } + + if (TYPE_CONTAINS_VPTR_P (type)) + /* Read and install the thunks. */ + while (tree vfunc = tree_node ()) + { + tree thunks = chained_decls (); + if (installing) + SET_DECL_THUNKS (vfunc, thunks); + } + + vec_free (vtables); + } + + /* Propagate to all variants. */ + if (installing) + fixup_type_variants (type); + + /* IS_FAKE_BASE_TYPE is inaccurate at this point, because if this is + the fake base, we've not hooked it into the containing class's + data structure yet. Fortunately it has a unique name. */ + if (installing + && DECL_NAME (defn) != as_base_identifier + && (!CLASSTYPE_TEMPLATE_INFO (type) + || !uses_template_parms (TI_ARGS (CLASSTYPE_TEMPLATE_INFO (type))))) + /* Emit debug info. It'd be nice to know if the interface TU + already emitted this. */ + rest_of_type_compilation (type, !LOCAL_CLASS_P (type)); + + vec_free (fields); + + return !get_overrun (); +} + +void +trees_out::write_enum_def (tree decl) +{ + tree type = TREE_TYPE (decl); + + tree_node (TYPE_VALUES (type)); + tree_node (TYPE_MIN_VALUE (type)); + tree_node (TYPE_MAX_VALUE (type)); +} + +void +trees_out::mark_enum_def (tree decl) +{ + tree type = TREE_TYPE (decl); + + for (tree values = TYPE_VALUES (type); values; values = TREE_CHAIN (values)) + { + tree cst = TREE_VALUE (values); + mark_by_value (cst); + /* We must mark the init to avoid circularity in tt_enum_int. */ + if (tree init = DECL_INITIAL (cst)) + if (TREE_CODE (init) == INTEGER_CST) + mark_by_value (init); + } +} + +bool +trees_in::read_enum_def (tree defn, tree maybe_template) +{ + tree type = TREE_TYPE (defn); + tree values = tree_node (); + tree min = tree_node (); + tree max = tree_node (); + + if (get_overrun ()) + return false; + + tree maybe_dup = odr_duplicate (maybe_template, TYPE_VALUES (type)); + bool installing = maybe_dup && !TYPE_VALUES (type); + + if (installing) + { + TYPE_VALUES (type) = values; + TYPE_MIN_VALUE (type) = min; + TYPE_MAX_VALUE (type) = max; + + rest_of_type_compilation (type, DECL_NAMESPACE_SCOPE_P (defn)); + } + else if (maybe_dup) + { + tree known = TYPE_VALUES (type); + for (; known && values; + known = TREE_CHAIN (known), values = TREE_CHAIN (values)) + { + tree known_decl = TREE_VALUE (known); + tree new_decl = TREE_VALUE (values); + + if (DECL_NAME (known_decl) != DECL_NAME (new_decl)) + goto bad; + + new_decl = maybe_duplicate (new_decl); + + if (!cp_tree_equal (DECL_INITIAL (known_decl), + DECL_INITIAL (new_decl))) + goto bad; + } + + if (known || values) + goto bad; + + if (!cp_tree_equal (TYPE_MIN_VALUE (type), min) + || !cp_tree_equal (TYPE_MAX_VALUE (type), max)) + { + bad:; + error_at (DECL_SOURCE_LOCATION (maybe_dup), + "definition of %qD does not match", maybe_dup); + inform (DECL_SOURCE_LOCATION (defn), + "existing definition %qD", defn); + + tree known_decl = NULL_TREE, new_decl = NULL_TREE; + + if (known) + known_decl = TREE_VALUE (known); + if (values) + new_decl = maybe_duplicate (TREE_VALUE (values)); + + if (known_decl && new_decl) + { + inform (DECL_SOURCE_LOCATION (new_decl), + "... this enumerator %qD", new_decl); + inform (DECL_SOURCE_LOCATION (known_decl), + "enumerator %qD does not match ...", known_decl); + } + else if (known_decl || new_decl) + { + tree extra = known_decl ? known_decl : new_decl; + inform (DECL_SOURCE_LOCATION (extra), + "additional enumerators beginning with %qD", extra); + } + else + inform (DECL_SOURCE_LOCATION (maybe_dup), + "enumeration range differs"); + + /* Mark it bad. */ + unmatched_duplicate (maybe_template); + } + } + + return true; +} + +/* Write out the body of DECL. See above circularity note. */ + +void +trees_out::write_definition (tree decl) +{ + if (streaming_p ()) + { + assert_definition (decl); + dump () + && dump ("Writing definition %C:%N", TREE_CODE (decl), decl); + } + else + dump (dumper::DEPEND) + && dump ("Depending definition %C:%N", TREE_CODE (decl), decl); + + again: + switch (TREE_CODE (decl)) + { + default: + gcc_unreachable (); + + case TEMPLATE_DECL: + decl = DECL_TEMPLATE_RESULT (decl); + goto again; + + case FUNCTION_DECL: + write_function_def (decl); + break; + + case TYPE_DECL: + { + tree type = TREE_TYPE (decl); + gcc_assert (TYPE_MAIN_VARIANT (type) == type + && TYPE_NAME (type) == decl); + if (TREE_CODE (type) == ENUMERAL_TYPE) + write_enum_def (decl); + else + write_class_def (decl); + } + break; + + case VAR_DECL: + case CONCEPT_DECL: + write_var_def (decl); + break; + } +} + +/* Mark a declaration for by-value walking. If DO_DEFN is true, mark + its body too. */ + +void +trees_out::mark_declaration (tree decl, bool do_defn) +{ + mark_by_value (decl); + + if (TREE_CODE (decl) == TEMPLATE_DECL) + decl = DECL_TEMPLATE_RESULT (decl); + + if (!do_defn) + return; + + switch (TREE_CODE (decl)) + { + default: + gcc_unreachable (); + + case FUNCTION_DECL: + mark_function_def (decl); + break; + + case TYPE_DECL: + { + tree type = TREE_TYPE (decl); + gcc_assert (TYPE_MAIN_VARIANT (type) == type + && TYPE_NAME (type) == decl); + if (TREE_CODE (type) == ENUMERAL_TYPE) + mark_enum_def (decl); + else + mark_class_def (decl); + } + break; + + case VAR_DECL: + case CONCEPT_DECL: + mark_var_def (decl); + break; + } +} + +/* Read in the body of DECL. See above circularity note. */ + +bool +trees_in::read_definition (tree decl) +{ + dump () && dump ("Reading definition %C %N", TREE_CODE (decl), decl); + + tree maybe_template = decl; + + again: + switch (TREE_CODE (decl)) + { + default: + break; + + case TEMPLATE_DECL: + decl = DECL_TEMPLATE_RESULT (decl); + goto again; + + case FUNCTION_DECL: + return read_function_def (decl, maybe_template); + + case TYPE_DECL: + { + tree type = TREE_TYPE (decl); + gcc_assert (TYPE_MAIN_VARIANT (type) == type + && TYPE_NAME (type) == decl); + if (TREE_CODE (type) == ENUMERAL_TYPE) + return read_enum_def (decl, maybe_template); + else + return read_class_def (decl, maybe_template); + } + break; + + case VAR_DECL: + case CONCEPT_DECL: + return read_var_def (decl, maybe_template); + } + + return false; +} + +/* Lookup an maybe insert a slot for depset for KEY. */ + +depset ** +depset::hash::entity_slot (tree entity, bool insert) +{ + traits::compare_type key (entity, NULL); + depset **slot = find_slot_with_hash (key, traits::hash (key), + insert ? INSERT : NO_INSERT); + + return slot; +} + +depset ** +depset::hash::binding_slot (tree ctx, tree name, bool insert) +{ + traits::compare_type key (ctx, name); + depset **slot = find_slot_with_hash (key, traits::hash (key), + insert ? INSERT : NO_INSERT); + + return slot; +} + +depset * +depset::hash::find_dependency (tree decl) +{ + depset **slot = entity_slot (decl, false); + + return slot ? *slot : NULL; +} + +depset * +depset::hash::find_binding (tree ctx, tree name) +{ + depset **slot = binding_slot (ctx, name, false); + + return slot ? *slot : NULL; +} + +/* DECL is a newly discovered dependency. Create the depset, if it + doesn't already exist. Add it to the worklist if so. + + DECL will be an OVL_USING_P OVERLOAD, if it's from a binding that's + a using decl. + + We do not have to worry about adding the same dependency more than + once. First it's harmless, but secondly the TREE_VISITED marking + prevents us wanting to do it anyway. */ + +depset * +depset::hash::make_dependency (tree decl, entity_kind ek) +{ + /* Make sure we're being told consistent information. */ + gcc_checking_assert ((ek == EK_NAMESPACE) + == (TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl))); + gcc_checking_assert (ek != EK_BINDING && ek != EK_REDIRECT); + gcc_checking_assert (TREE_CODE (decl) != FIELD_DECL + && (TREE_CODE (decl) != USING_DECL + || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)); + gcc_checking_assert (!is_key_order ()); + if (ek == EK_USING) + gcc_checking_assert (TREE_CODE (decl) == OVERLOAD); + + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + /* The template should have copied these from its result decl. */ + tree res = DECL_TEMPLATE_RESULT (decl); + + gcc_checking_assert (DECL_MODULE_EXPORT_P (decl) + == DECL_MODULE_EXPORT_P (res)); + if (DECL_LANG_SPECIFIC (res)) + { + gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl) + == DECL_MODULE_PURVIEW_P (res)); + gcc_checking_assert ((DECL_MODULE_IMPORT_P (decl) + == DECL_MODULE_IMPORT_P (res))); + } + } + + depset **slot = entity_slot (decl, true); + depset *dep = *slot; + bool for_binding = ek == EK_FOR_BINDING; + + if (!dep) + { + if (DECL_IMPLICIT_TYPEDEF_P (decl) + /* ... not an enum, for instance. */ + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + && TYPE_LANG_SPECIFIC (TREE_TYPE (decl)) + && CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)) == 2) + { + /* A partial or explicit specialization. Partial + specializations might not be in the hash table, because + there can be multiple differently-constrained variants. + + template<typename T> class silly; + template<typename T> requires true class silly {}; + + We need to find them, insert their TEMPLATE_DECL in the + dep_hash, and then convert the dep we just found into a + redirect. */ + + tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (decl)); + tree tmpl = TI_TEMPLATE (ti); + tree partial = NULL_TREE; + for (tree spec = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); + spec; spec = TREE_CHAIN (spec)) + if (DECL_TEMPLATE_RESULT (TREE_VALUE (spec)) == decl) + { + partial = TREE_VALUE (spec); + break; + } + + if (partial) + { + /* Eagerly create an empty redirect. The following + make_dependency call could cause hash reallocation, + and invalidate slot's value. */ + depset *redirect = make_entity (decl, EK_REDIRECT); + + /* Redirects are never reached -- always snap to their target. */ + redirect->set_flag_bit<DB_UNREACHED_BIT> (); + + *slot = redirect; + + depset *tmpl_dep = make_dependency (partial, EK_PARTIAL); + gcc_checking_assert (tmpl_dep->get_entity_kind () == EK_PARTIAL); + + redirect->deps.safe_push (tmpl_dep); + + return redirect; + } + } + + bool has_def = ek != EK_USING && has_definition (decl); + if (ek > EK_BINDING) + ek = EK_DECL; + + /* The only OVERLOADS we should see are USING decls from + bindings. */ + *slot = dep = make_entity (decl, ek, has_def); + + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + if (DECL_ALIAS_TEMPLATE_P (decl) && DECL_TEMPLATE_INFO (decl)) + dep->set_flag_bit<DB_ALIAS_TMPL_INST_BIT> (); + else if (CHECKING_P) + /* The template_result should otherwise not be in the + table, or be an empty redirect (created above). */ + if (auto *eslot = entity_slot (DECL_TEMPLATE_RESULT (decl), false)) + gcc_checking_assert ((*eslot)->get_entity_kind () == EK_REDIRECT + && !(*eslot)->deps.length ()); + } + + if (ek != EK_USING + && DECL_LANG_SPECIFIC (decl) + && DECL_MODULE_IMPORT_P (decl)) + { + /* Store the module number and index in cluster/section, so + we don't have to look them up again. */ + unsigned index = import_entity_index (decl); + module_state *from = import_entity_module (index); + /* Remap will be zero for imports from partitions, which we + want to treat as-if declared in this TU. */ + if (from->remap) + { + dep->cluster = index - from->entity_lwm; + dep->section = from->remap; + dep->set_flag_bit<DB_IMPORTED_BIT> (); + } + } + + if (ek == EK_DECL + && !dep->is_import () + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL + && !(TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))) + { + tree ctx = CP_DECL_CONTEXT (decl); + tree not_tmpl = STRIP_TEMPLATE (decl); + + if (!TREE_PUBLIC (ctx)) + /* Member of internal namespace. */ + dep->set_flag_bit<DB_IS_INTERNAL_BIT> (); + else if (VAR_OR_FUNCTION_DECL_P (not_tmpl) + && DECL_THIS_STATIC (not_tmpl)) + { + /* An internal decl. This is ok in a GM entity. */ + if (!(header_module_p () + || !DECL_LANG_SPECIFIC (not_tmpl) + || !DECL_MODULE_PURVIEW_P (not_tmpl))) + dep->set_flag_bit<DB_IS_INTERNAL_BIT> (); + } + + } + + if (!dep->is_import ()) + worklist.safe_push (dep); + } + + dump (dumper::DEPEND) + && dump ("%s on %s %C:%N found", + ek == EK_REDIRECT ? "Redirect" + : for_binding ? "Binding" : "Dependency", + dep->entity_kind_name (), TREE_CODE (decl), decl); + + return dep; +} + +/* DEP is a newly discovered dependency. Append it to current's + depset. */ + +void +depset::hash::add_dependency (depset *dep) +{ + gcc_checking_assert (current && !is_key_order ()); + current->deps.safe_push (dep); + + if (dep->is_internal () && !current->is_internal ()) + current->set_flag_bit<DB_REFS_INTERNAL_BIT> (); + + if (current->get_entity_kind () == EK_USING + && DECL_IMPLICIT_TYPEDEF_P (dep->get_entity ()) + && TREE_CODE (TREE_TYPE (dep->get_entity ())) == ENUMERAL_TYPE) + { + /* CURRENT is an unwrapped using-decl and DECL is an enum's + implicit typedef. Is CURRENT a member of the enum? */ + tree c_decl = OVL_FUNCTION (current->get_entity ()); + + if (TREE_CODE (c_decl) == CONST_DECL + && (current->deps[0]->get_entity () + == CP_DECL_CONTEXT (dep->get_entity ()))) + /* Make DECL depend on CURRENT. */ + dep->deps.safe_push (current); + } + + if (dep->is_unreached ()) + { + /* The dependency is reachable now. */ + reached_unreached = true; + dep->clear_flag_bit<DB_UNREACHED_BIT> (); + dump (dumper::DEPEND) + && dump ("Reaching unreached %s %C:%N", dep->entity_kind_name (), + TREE_CODE (dep->get_entity ()), dep->get_entity ()); + } +} + +depset * +depset::hash::add_dependency (tree decl, entity_kind ek) +{ + depset *dep; + + if (is_key_order ()) + { + dep = find_dependency (decl); + if (dep) + { + current->deps.safe_push (dep); + dump (dumper::MERGE) + && dump ("Key dependency on %s %C:%N found", + dep->entity_kind_name (), TREE_CODE (decl), decl); + } + else + { + /* It's not a mergeable decl, look for it in the original + table. */ + dep = chain->find_dependency (decl); + gcc_checking_assert (dep); + } + } + else + { + dep = make_dependency (decl, ek); + if (dep->get_entity_kind () != EK_REDIRECT) + add_dependency (dep); + } + + return dep; +} + +void +depset::hash::add_namespace_context (depset *dep, tree ns) +{ + depset *ns_dep = make_dependency (ns, depset::EK_NAMESPACE); + dep->deps.safe_push (ns_dep); + + /* Mark it as special if imported so we don't walk connect when + SCCing. */ + if (!dep->is_binding () && ns_dep->is_import ()) + dep->set_special (); +} + +struct add_binding_data +{ + tree ns; + bitmap partitions; + depset *binding; + depset::hash *hash; + bool met_namespace; +}; + +bool +depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) +{ + auto data = static_cast <add_binding_data *> (data_); + + if (TREE_CODE (decl) != NAMESPACE_DECL || DECL_NAMESPACE_ALIAS (decl)) + { + tree inner = decl; + + if (TREE_CODE (inner) == CONST_DECL + && TREE_CODE (DECL_CONTEXT (inner)) == ENUMERAL_TYPE) + inner = TYPE_NAME (DECL_CONTEXT (inner)); + else if (TREE_CODE (inner) == TEMPLATE_DECL) + inner = DECL_TEMPLATE_RESULT (inner); + + if (!DECL_LANG_SPECIFIC (inner) || !DECL_MODULE_PURVIEW_P (inner)) + /* Ignore global module fragment entities. */ + return false; + + if (VAR_OR_FUNCTION_DECL_P (inner) + && DECL_THIS_STATIC (inner)) + { + if (!header_module_p ()) + /* Ignore internal-linkage entitites. */ + return false; + } + + if ((TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == TYPE_DECL) + && DECL_TINFO_P (decl)) + /* Ignore TINFO things. */ + return false; + + if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns) + { + /* A using that lost its wrapper or an unscoped enum + constant. */ + flags = WMB_Flags (flags | WMB_Using); + if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL + ? TYPE_NAME (TREE_TYPE (decl)) + : STRIP_TEMPLATE (decl))) + flags = WMB_Flags (flags | WMB_Export); + } + + if (!data->binding) + /* No binding to check. */; + else if (flags & WMB_Using) + { + /* Look in the binding to see if we already have this + using. */ + for (unsigned ix = data->binding->deps.length (); --ix;) + { + depset *d = data->binding->deps[ix]; + if (d->get_entity_kind () == EK_USING + && OVL_FUNCTION (d->get_entity ()) == decl) + { + if (!(flags & WMB_Hidden)) + d->clear_hidden_binding (); + if (flags & WMB_Export) + OVL_EXPORT_P (d->get_entity ()) = true; + return false; + } + } + } + else if (flags & WMB_Dups) + { + /* Look in the binding to see if we already have this decl. */ + for (unsigned ix = data->binding->deps.length (); --ix;) + { + depset *d = data->binding->deps[ix]; + if (d->get_entity () == decl) + { + if (!(flags & WMB_Hidden)) + d->clear_hidden_binding (); + return false; + } + } + } + + /* We're adding something. */ + if (!data->binding) + { + data->binding = make_binding (data->ns, DECL_NAME (decl)); + data->hash->add_namespace_context (data->binding, data->ns); + + depset **slot = data->hash->binding_slot (data->ns, + DECL_NAME (decl), true); + gcc_checking_assert (!*slot); + *slot = data->binding; + } + + if (flags & WMB_Using) + { + decl = ovl_make (decl, NULL_TREE); + if (flags & WMB_Export) + OVL_EXPORT_P (decl) = true; + } + + depset *dep = data->hash->make_dependency + (decl, flags & WMB_Using ? EK_USING : EK_FOR_BINDING); + if (flags & WMB_Hidden) + dep->set_hidden_binding (); + data->binding->deps.safe_push (dep); + /* Binding and contents are mutually dependent. */ + dep->deps.safe_push (data->binding); + + return true; + } + else if (DECL_NAME (decl) && !data->met_namespace) + { + /* Namespace, walk exactly once. */ + gcc_checking_assert (TREE_PUBLIC (decl)); + data->met_namespace = true; + if (data->hash->add_namespace_entities (decl, data->partitions) + || DECL_MODULE_EXPORT_P (decl)) + { + data->hash->make_dependency (decl, depset::EK_NAMESPACE); + return true; + } + } + + return false; +} + +/* Recursively find all the namespace bindings of NS. + Add a depset for every binding that contains an export or + module-linkage entity. Add a defining depset for every such decl + that we need to write a definition. Such defining depsets depend + on the binding depset. Returns true if we contain something + explicitly exported. */ + +bool +depset::hash::add_namespace_entities (tree ns, bitmap partitions) +{ + dump () && dump ("Looking for writables in %N", ns); + dump.indent (); + + unsigned count = 0; + add_binding_data data; + data.ns = ns; + data.partitions = partitions; + data.hash = this; + + 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) + { + data.binding = nullptr; + data.met_namespace = false; + if (walk_module_binding (*iter, partitions, add_binding_entity, &data)) + count++; + } + + if (count) + dump () && dump ("Found %u entries", count); + dump.outdent (); + + return count != 0; +} + +void +depset::hash::add_partial_entities (vec<tree, va_gc> *partial_classes) +{ + for (unsigned ix = 0; ix != partial_classes->length (); ix++) + { + tree inner = (*partial_classes)[ix]; + + depset *dep = make_dependency (inner, depset::EK_DECL); + + if (dep->get_entity_kind () == depset::EK_REDIRECT) + /* We should have recorded the template as a partial + specialization. */ + gcc_checking_assert (dep->deps[0]->get_entity_kind () + == depset::EK_PARTIAL); + else + /* It was an explicit specialization, not a partial one. */ + gcc_checking_assert (dep->get_entity_kind () + == depset::EK_SPECIALIZATION); + } +} + +/* Add the members of imported classes that we defined in this TU. + This will also include lazily created implicit member function + declarations. (All others will be definitions.) */ + +void +depset::hash::add_class_entities (vec<tree, va_gc> *class_members) +{ + for (unsigned ix = 0; ix != class_members->length (); ix++) + { + tree defn = (*class_members)[ix]; + depset *dep = make_dependency (defn, EK_INNER_DECL); + + if (dep->get_entity_kind () == EK_REDIRECT) + dep = dep->deps[0]; + + /* Only non-instantiations need marking as members. */ + if (dep->get_entity_kind () == EK_DECL) + dep->set_flag_bit <DB_IS_MEMBER_BIT> (); + } +} + +/* We add the partial & explicit specializations, and the explicit + instantiations. */ + +static void +specialization_add (bool decl_p, spec_entry *entry, void *data_) +{ + vec<spec_entry *> *data = reinterpret_cast <vec<spec_entry *> *> (data_); + + if (!decl_p) + { + /* We exclusively use decls to locate things. Make sure there's + no mismatch between the two specialization tables we keep. + pt.c optimizes instantiation lookup using a complicated + heuristic. We don't attempt to replicate that algorithm, but + observe its behaviour and reproduce it upon read back. */ + + gcc_checking_assert (DECL_ALIAS_TEMPLATE_P (entry->tmpl) + || TREE_CODE (entry->spec) == ENUMERAL_TYPE + || DECL_CLASS_TEMPLATE_P (entry->tmpl)); + + /* Only alias templates can appear in both tables (and + if they're in the type table they must also be in the decl table). */ + gcc_checking_assert + (!match_mergeable_specialization (true, entry, false) + == (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl))); + } + else if (VAR_OR_FUNCTION_DECL_P (entry->spec)) + gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec)); + + data->safe_push (entry); +} + +/* Arbitrary stable comparison. */ + +static int +specialization_cmp (const void *a_, const void *b_) +{ + const spec_entry *ea = *reinterpret_cast<const spec_entry *const *> (a_); + const spec_entry *eb = *reinterpret_cast<const spec_entry *const *> (b_); + + if (ea == eb) + return 0; + + tree a = ea->spec; + tree b = eb->spec; + if (TYPE_P (a)) + { + a = TYPE_NAME (a); + b = TYPE_NAME (b); + } + + if (a == b) + /* This can happen with friend specializations. Just order by + entry address. See note in depset_cmp. */ + return ea < eb ? -1 : +1; + + return DECL_UID (a) < DECL_UID (b) ? -1 : +1; +} + +/* We add all kinds of specialializations. Implicit specializations + should only streamed and walked if they are reachable from + elsewhere. Hence the UNREACHED flag. This is making the + assumption that it is cheaper to reinstantiate them on demand + elsewhere, rather than stream them in when we instantiate their + general template. Also, if we do stream them, we can only do that + if they are not internal (which they can become if they themselves + touch an internal entity?). */ + +void +depset::hash::add_specializations (bool decl_p) +{ + vec<spec_entry *> data; + data.create (100); + walk_specializations (decl_p, specialization_add, &data); + data.qsort (specialization_cmp); + while (data.length ()) + { + spec_entry *entry = data.pop (); + tree spec = entry->spec; + int use_tpl = 0; + bool is_alias = false; + bool is_friend = false; + + if (decl_p && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (entry->tmpl)) + /* A friend of a template. This is keyed to the + instantiation. */ + is_friend = true; + + if (!decl_p && DECL_ALIAS_TEMPLATE_P (entry->tmpl)) + { + spec = TYPE_NAME (spec); + is_alias = true; + } + + if (decl_p || is_alias) + { + if (tree ti = DECL_TEMPLATE_INFO (spec)) + { + tree tmpl = TI_TEMPLATE (ti); + + use_tpl = DECL_USE_TEMPLATE (spec); + if (spec == DECL_TEMPLATE_RESULT (tmpl)) + { + spec = tmpl; + gcc_checking_assert (DECL_USE_TEMPLATE (spec) == use_tpl); + } + else if (is_friend) + { + if (TI_TEMPLATE (ti) != entry->tmpl + || !template_args_equal (TI_ARGS (ti), entry->tmpl)) + goto template_friend; + } + } + else + { + template_friend:; + gcc_checking_assert (is_friend); + /* This is a friend of a template class, but not the one + that generated entry->spec itself (i.e. it's an + equivalent clone). We do not need to record + this. */ + continue; + } + } + else + { + if (TREE_CODE (spec) == ENUMERAL_TYPE) + { + tree ctx = DECL_CONTEXT (TYPE_NAME (spec)); + + if (TYPE_P (ctx)) + use_tpl = CLASSTYPE_USE_TEMPLATE (ctx); + else + use_tpl = DECL_USE_TEMPLATE (ctx); + } + else + use_tpl = CLASSTYPE_USE_TEMPLATE (spec); + + tree ti = TYPE_TEMPLATE_INFO (spec); + tree tmpl = TI_TEMPLATE (ti); + + spec = TYPE_NAME (spec); + if (spec == DECL_TEMPLATE_RESULT (tmpl)) + { + spec = tmpl; + use_tpl = DECL_USE_TEMPLATE (spec); + } + } + + bool needs_reaching = false; + if (use_tpl == 1) + /* Implicit instantiations only walked if we reach them. */ + needs_reaching = true; + else if (!DECL_LANG_SPECIFIC (spec) + || !DECL_MODULE_PURVIEW_P (spec)) + /* Likewise, GMF explicit or partial specializations. */ + needs_reaching = true; + +#if false && CHECKING_P + /* The instantiation isn't always on + DECL_TEMPLATE_INSTANTIATIONS, */ + // FIXME: we probably need to remember this information? + /* Verify the specialization is on the + DECL_TEMPLATE_INSTANTIATIONS of the template. */ + for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (entry->tmpl); + cons; cons = TREE_CHAIN (cons)) + if (TREE_VALUE (cons) == entry->spec) + { + gcc_assert (entry->args == TREE_PURPOSE (cons)); + goto have_spec; + } + gcc_unreachable (); + have_spec:; +#endif + + depset *dep = make_dependency (spec, depset::EK_SPECIALIZATION); + if (dep->is_special ()) + { + /* An already located specialization, this must be the TYPE + corresponding to an alias_decl we found in the decl + table. */ + spec_entry *other = reinterpret_cast <spec_entry *> (dep->deps[0]); + gcc_checking_assert (!decl_p && is_alias && !dep->is_type_spec ()); + gcc_checking_assert (other->tmpl == entry->tmpl + && template_args_equal (other->args, entry->args) + && TREE_TYPE (other->spec) == entry->spec); + dep->set_flag_bit<DB_ALIAS_SPEC_BIT> (); + } + else + { + gcc_checking_assert (decl_p || !is_alias); + if (dep->get_entity_kind () == depset::EK_REDIRECT) + dep = dep->deps[0]; + else if (dep->get_entity_kind () == depset::EK_SPECIALIZATION) + { + dep->set_special (); + dep->deps.safe_push (reinterpret_cast<depset *> (entry)); + if (!decl_p) + dep->set_flag_bit<DB_TYPE_SPEC_BIT> (); + } + + if (needs_reaching) + dep->set_flag_bit<DB_UNREACHED_BIT> (); + if (is_friend) + dep->set_flag_bit<DB_FRIEND_SPEC_BIT> (); + } + } + data.release (); +} + +/* Add a depset into the mergeable hash. */ + +void +depset::hash::add_mergeable (depset *mergeable) +{ + gcc_checking_assert (is_key_order ()); + entity_kind ek = mergeable->get_entity_kind (); + tree decl = mergeable->get_entity (); + gcc_checking_assert (ek < EK_DIRECT_HWM); + + depset **slot = entity_slot (decl, true); + gcc_checking_assert (!*slot); + depset *dep = make_entity (decl, ek); + *slot = dep; + + worklist.safe_push (dep); + + /* So we can locate the mergeable depset this depset refers to, + mark the first dep. */ + dep->set_special (); + dep->deps.safe_push (mergeable); +} + +/* Iteratively find dependencies. During the walk we may find more + entries on the same binding that need walking. */ + +void +depset::hash::find_dependencies (module_state *module) +{ + trees_out walker (NULL, module, *this); + vec<depset *> unreached; + unreached.create (worklist.length ()); + + for (;;) + { + reached_unreached = false; + while (worklist.length ()) + { + depset *item = worklist.pop (); + + gcc_checking_assert (!item->is_binding ()); + if (item->is_unreached ()) + unreached.quick_push (item); + else + { + current = item; + tree decl = current->get_entity (); + dump (is_key_order () ? dumper::MERGE : dumper::DEPEND) + && dump ("Dependencies of %s %C:%N", + is_key_order () ? "key-order" + : current->entity_kind_name (), TREE_CODE (decl), decl); + dump.indent (); + walker.begin (); + if (current->get_entity_kind () == EK_USING) + walker.tree_node (OVL_FUNCTION (decl)); + else if (TREE_VISITED (decl)) + /* A global tree. */; + else if (TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl)) + add_namespace_context (current, CP_DECL_CONTEXT (decl)); + else + { + walker.mark_declaration (decl, current->has_defn ()); + + // FIXME: Perhaps p1815 makes this redundant? Or at + // least simplifies it. Voldemort types are only + // ever emissable when containing (inline) function + // definition is emitted? + /* Turn the Sneakoscope on when depending the decl. */ + sneakoscope = true; + walker.decl_value (decl, current); + sneakoscope = false; + if (current->has_defn ()) + walker.write_definition (decl); + } + walker.end (); + + if (!walker.is_key_order () + && TREE_CODE (decl) == TEMPLATE_DECL + && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + /* Mark all the explicit & partial specializations as + reachable. */ + for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl); + cons; cons = TREE_CHAIN (cons)) + { + tree spec = TREE_VALUE (cons); + if (TYPE_P (spec)) + spec = TYPE_NAME (spec); + int use_tpl; + node_template_info (spec, use_tpl); + if (use_tpl & 2) + { + depset *spec_dep = find_dependency (spec); + if (spec_dep->get_entity_kind () == EK_REDIRECT) + spec_dep = spec_dep->deps[0]; + if (spec_dep->is_unreached ()) + { + reached_unreached = true; + spec_dep->clear_flag_bit<DB_UNREACHED_BIT> (); + dump (dumper::DEPEND) + && dump ("Reaching unreached specialization" + " %C:%N", TREE_CODE (spec), spec); + } + } + } + + dump.outdent (); + current = NULL; + } + } + + if (!reached_unreached) + break; + + /* It's possible the we reached the unreached before we + processed it in the above loop, so we'll be doing this an + extra time. However, to avoid that we have to do some + bit shuffling that also involves a scan of the list. + Swings & roundabouts I guess. */ + std::swap (worklist, unreached); + } + + unreached.release (); +} + +/* Compare two entries of a single binding. TYPE_DECL before + non-exported before exported. */ + +static int +binding_cmp (const void *a_, const void *b_) +{ + depset *a = *(depset *const *)a_; + depset *b = *(depset *const *)b_; + + tree a_ent = a->get_entity (); + tree b_ent = b->get_entity (); + gcc_checking_assert (a_ent != b_ent + && !a->is_binding () + && !b->is_binding ()); + + /* Implicit typedefs come first. */ + bool a_implicit = DECL_IMPLICIT_TYPEDEF_P (a_ent); + bool b_implicit = DECL_IMPLICIT_TYPEDEF_P (b_ent); + if (a_implicit || b_implicit) + { + /* A binding with two implicit type decls? That's unpossible! */ + gcc_checking_assert (!(a_implicit && b_implicit)); + return a_implicit ? -1 : +1; /* Implicit first. */ + } + + /* Hidden before non-hidden. */ + bool a_hidden = a->is_hidden (); + bool b_hidden = b->is_hidden (); + if (a_hidden != b_hidden) + return a_hidden ? -1 : +1; + + bool a_using = a->get_entity_kind () == depset::EK_USING; + bool a_export; + if (a_using) + { + a_export = OVL_EXPORT_P (a_ent); + a_ent = OVL_FUNCTION (a_ent); + } + else + a_export = DECL_MODULE_EXPORT_P (TREE_CODE (a_ent) == CONST_DECL + ? TYPE_NAME (TREE_TYPE (a_ent)) + : STRIP_TEMPLATE (a_ent)); + + bool b_using = b->get_entity_kind () == depset::EK_USING; + bool b_export; + if (b_using) + { + b_export = OVL_EXPORT_P (b_ent); + b_ent = OVL_FUNCTION (b_ent); + } + else + b_export = DECL_MODULE_EXPORT_P (TREE_CODE (b_ent) == CONST_DECL + ? TYPE_NAME (TREE_TYPE (b_ent)) + : STRIP_TEMPLATE (b_ent)); + + /* Non-exports before exports. */ + if (a_export != b_export) + return a_export ? +1 : -1; + + /* At this point we don't care, but want a stable sort. */ + + if (a_using != b_using) + /* using first. */ + return a_using? -1 : +1; + + return DECL_UID (a_ent) < DECL_UID (b_ent) ? -1 : +1; +} + +/* Sort the bindings, issue errors about bad internal refs. */ + +bool +depset::hash::finalize_dependencies () +{ + bool ok = true; + depset::hash::iterator end (this->end ()); + for (depset::hash::iterator iter (begin ()); iter != end; ++iter) + { + depset *dep = *iter; + if (dep->is_binding ()) + { + /* Keep the containing namespace dep first. */ + gcc_checking_assert (dep->deps.length () > 1 + && (dep->deps[0]->get_entity_kind () + == EK_NAMESPACE) + && (dep->deps[0]->get_entity () + == dep->get_entity ())); + if (dep->deps.length () > 2) + gcc_qsort (&dep->deps[1], dep->deps.length () - 1, + sizeof (dep->deps[1]), binding_cmp); + } + else if (dep->refs_internal ()) + { + for (unsigned ix = dep->deps.length (); ix--;) + { + depset *rdep = dep->deps[ix]; + if (rdep->is_internal ()) + { + // FIXME:QOI Better location information? We're + // losing, so it doesn't matter about efficiency + tree decl = dep->get_entity (); + error_at (DECL_SOURCE_LOCATION (decl), + "%q#D references internal linkage entity %q#D", + decl, rdep->get_entity ()); + break; + } + } + ok = false; + } + } + + return ok; +} + +/* Core of TARJAN's algorithm to find Strongly Connected Components + within a graph. See https://en.wikipedia.org/wiki/ + Tarjan%27s_strongly_connected_components_algorithm for details. + + We use depset::section as lowlink. Completed nodes have + depset::cluster containing the cluster number, with the top + bit set. + + A useful property is that the output vector is a reverse + topological sort of the resulting DAG. In our case that means + dependent SCCs are found before their dependers. We make use of + that property. */ + +void +depset::tarjan::connect (depset *v) +{ + gcc_checking_assert (v->is_binding () + || !(v->is_unreached () || v->is_import ())); + + v->cluster = v->section = ++index; + stack.safe_push (v); + + /* Walk all our dependencies, ignore a first marked slot */ + for (unsigned ix = v->is_special (); ix != v->deps.length (); ix++) + { + depset *dep = v->deps[ix]; + + if (dep->is_binding () || !dep->is_import ()) + { + unsigned lwm = dep->cluster; + + if (!dep->cluster) + { + /* A new node. Connect it. */ + connect (dep); + lwm = dep->section; + } + + if (dep->section && v->section > lwm) + v->section = lwm; + } + } + + if (v->section == v->cluster) + { + /* Root of a new SCC. Push all the members onto the result list. */ + unsigned num = v->cluster; + depset *p; + do + { + p = stack.pop (); + p->cluster = num; + p->section = 0; + result.quick_push (p); + } + while (p != v); + } +} + +/* Compare two depsets. The specific ordering is unimportant, we're + just trying to get consistency. */ + +static int +depset_cmp (const void *a_, const void *b_) +{ + depset *a = *(depset *const *)a_; + depset *b = *(depset *const *)b_; + + depset::entity_kind a_kind = a->get_entity_kind (); + depset::entity_kind b_kind = b->get_entity_kind (); + + if (a_kind != b_kind) + /* Different entity kinds, order by that. */ + return a_kind < b_kind ? -1 : +1; + + tree a_decl = a->get_entity (); + tree b_decl = b->get_entity (); + if (a_kind == depset::EK_USING) + { + /* If one is a using, the other must be too. */ + a_decl = OVL_FUNCTION (a_decl); + b_decl = OVL_FUNCTION (b_decl); + } + + if (a_decl != b_decl) + /* Different entities, order by their UID. */ + return DECL_UID (a_decl) < DECL_UID (b_decl) ? -1 : +1; + + if (a_kind == depset::EK_BINDING) + { + /* Both are bindings. Order by identifier hash. */ + gcc_checking_assert (a->get_name () != b->get_name ()); + return (IDENTIFIER_HASH_VALUE (a->get_name ()) + < IDENTIFIER_HASH_VALUE (b->get_name ()) + ? -1 : +1); + } + + /* They are the same decl. This can happen with two using decls + pointing to the same target. The best we can aim for is + consistently telling qsort how to order them. Hopefully we'll + never have to debug a case that depends on this. Oh, who am I + kidding? Good luck. */ + gcc_checking_assert (a_kind == depset::EK_USING); + + /* Order by depset address. Not the best, but it is something. */ + return a < b ? -1 : +1; +} + +/* Sort the clusters in SCC such that those that depend on one another + are placed later. */ + +// FIXME: I am not convinced this is needed and, if needed, +// sufficient. We emit the decls in this order but that emission +// could walk into later decls (from the body of the decl, or default +// arg-like things). Why doesn't that walk do the right thing? And +// if it DTRT why do we need to sort here -- won't things naturally +// work? I think part of the issue is that when we're going to refer +// to an entity by name, and that entity is in the same cluster as us, +// we need to actually walk that entity, if we've not already walked +// it. +static void +sort_cluster (depset::hash *original, depset *scc[], unsigned size) +{ + depset::hash table (size, original); + + dump.indent (); + + /* Place bindings last, usings before that. It's not strictly + necessary, but it does make things neater. Says Mr OCD. */ + unsigned bind_lwm = size; + unsigned use_lwm = size; + for (unsigned ix = 0; ix != use_lwm;) + { + depset *dep = scc[ix]; + switch (dep->get_entity_kind ()) + { + case depset::EK_BINDING: + /* Move to end. No increment. Notice this could be moving + a using decl, which we'll then move again. */ + if (--bind_lwm != ix) + { + scc[ix] = scc[bind_lwm]; + scc[bind_lwm] = dep; + } + if (use_lwm > bind_lwm) + { + use_lwm--; + break; + } + /* We must have copied a using, so move it too. */ + dep = scc[ix]; + gcc_checking_assert (dep->get_entity_kind () == depset::EK_USING); + /* FALLTHROUGH */ + + case depset::EK_USING: + if (--use_lwm != ix) + { + scc[ix] = scc[use_lwm]; + scc[use_lwm] = dep; + } + break; + + case depset::EK_DECL: + case depset::EK_SPECIALIZATION: + case depset::EK_PARTIAL: + table.add_mergeable (dep); + ix++; + break; + + default: + gcc_unreachable (); + } + } + + gcc_checking_assert (use_lwm <= bind_lwm); + dump (dumper::MERGE) && dump ("Ordering %u/%u depsets", use_lwm, size); + + table.find_dependencies (nullptr); + + vec<depset *> order = table.connect (); + gcc_checking_assert (order.length () == use_lwm); + + /* Now rewrite entries [0,lwm), in the dependency order we + discovered. Usually each entity is in its own cluster. Rarely, + we can get multi-entity clusters, in which case all but one must + only be reached from within the cluster. This happens for + something like: + + template<typename T> + auto Foo (const T &arg) -> TPL<decltype (arg)>; + + The instantiation of TPL will be in the specialization table, and + refer to Foo via arg. But we can only get to that specialization + from Foo's declaration, so we only need to treat Foo as mergable + (We'll do structural comparison of TPL<decltype (arg)>). + + Finding the single cluster entry dep is very tricky and + expensive. Let's just not do that. It's harmless in this case + anyway. */ + unsigned pos = 0; + unsigned cluster = ~0u; + for (unsigned ix = 0; ix != order.length (); ix++) + { + gcc_checking_assert (order[ix]->is_special ()); + depset *dep = order[ix]->deps[0]; + scc[pos++] = dep; + dump (dumper::MERGE) + && dump ("Mergeable %u is %N%s", ix, dep->get_entity (), + order[ix]->cluster == cluster ? " (tight)" : ""); + cluster = order[ix]->cluster; + } + + gcc_checking_assert (pos == use_lwm); + + order.release (); + dump (dumper::MERGE) && dump ("Ordered %u keys", pos); + dump.outdent (); +} + +/* Reduce graph to SCCS clusters. SCCS will be populated with the + depsets in dependency order. Each depset's CLUSTER field contains + its cluster number. Each SCC has a unique cluster number, and are + contiguous in SCCS. Cluster numbers are otherwise arbitrary. */ + +vec<depset *> +depset::hash::connect () +{ + tarjan connector (size ()); + vec<depset *> deps; + deps.create (size ()); + iterator end (this->end ()); + for (iterator iter (begin ()); iter != end; ++iter) + { + depset *item = *iter; + + entity_kind kind = item->get_entity_kind (); + if (kind == EK_BINDING + || !(kind == EK_REDIRECT + || item->is_unreached () + || item->is_import ())) + deps.quick_push (item); + } + + /* Iteration over the hash table is an unspecified ordering. While + that has advantages, it causes 2 problems. Firstly repeatable + builds are tricky. Secondly creating testcases that check + dependencies are correct by making sure a bad ordering would + happen if that was wrong. */ + deps.qsort (depset_cmp); + + while (deps.length ()) + { + depset *v = deps.pop (); + dump (dumper::CLUSTER) && + (v->is_binding () + ? dump ("Connecting binding %P", v->get_entity (), v->get_name ()) + : dump ("Connecting %s %s %C:%N", + is_key_order () ? "key-order" + : !v->has_defn () ? "declaration" : "definition", + v->entity_kind_name (), TREE_CODE (v->get_entity ()), + v->get_entity ())); + if (!v->cluster) + connector.connect (v); + } + + deps.release (); + return connector.result; +} + +/* Load the entities referred to by this pendset. */ + +static bool +pendset_lazy_load (pendset *pendings, bool specializations_p) +{ + bool ok = true; + + for (unsigned ix = 0; ok && ix != pendings->num; ix++) + { + unsigned index = pendings->values[ix]; + if (index & ~(~0u >> 1)) + { + /* An indirection. */ + if (specializations_p) + index = ~index; + pendset *other = pending_table->get (index, true); + if (!pendset_lazy_load (other, specializations_p)) + ok = false; + } + else + { + module_state *module = import_entity_module (index); + binding_slot *slot = &(*entity_ary)[index]; + if (!slot->is_lazy ()) + dump () && dump ("Specialiation %M[%u] already loaded", + module, index - module->entity_lwm); + else if (!module->lazy_load (index - module->entity_lwm, slot)) + ok = false; + } + } + + /* We own set, so delete it now. */ + delete pendings; + + return ok; +} + +/* Initialize location spans. */ + +void +loc_spans::init (const line_maps *lmaps, const line_map_ordinary *map) +{ + gcc_checking_assert (!init_p ()); + spans = new vec<span> (); + spans->reserve (20); + + span interval; + interval.ordinary.first = 0; + interval.macro.second = MAX_LOCATION_T + 1; + interval.ordinary_delta = interval.macro_delta = 0; + + /* A span for reserved fixed locs. */ + interval.ordinary.second + = MAP_START_LOCATION (LINEMAPS_ORDINARY_MAP_AT (line_table, 0)); + interval.macro.first = interval.macro.second; + dump (dumper::LOCATION) + && dump ("Fixed span %u ordinary:[%u,%u) macro:[%u,%u)", spans->length (), + interval.ordinary.first, interval.ordinary.second, + interval.macro.first, interval.macro.second); + spans->quick_push (interval); + + /* A span for command line & forced headers. */ + interval.ordinary.first = interval.ordinary.second; + interval.macro.second = interval.macro.first; + if (map) + { + interval.ordinary.second = map->start_location; + interval.macro.first = LINEMAPS_MACRO_LOWEST_LOCATION (lmaps); + } + dump (dumper::LOCATION) + && dump ("Pre span %u ordinary:[%u,%u) macro:[%u,%u)", spans->length (), + interval.ordinary.first, interval.ordinary.second, + interval.macro.first, interval.macro.second); + spans->quick_push (interval); + + /* Start an interval for the main file. */ + interval.ordinary.first = interval.ordinary.second; + interval.macro.second = interval.macro.first; + dump (dumper::LOCATION) + && dump ("Main span %u ordinary:[%u,*) macro:[*,%u)", spans->length (), + interval.ordinary.first, interval.macro.second); + spans->quick_push (interval); +} + +/* Reopen the span, if we want the about-to-be-inserted set of maps to + be propagated in our own location table. I.e. we are the primary + interface and we're importing a partition. */ + +bool +loc_spans::maybe_propagate (module_state *import, + location_t loc = UNKNOWN_LOCATION) +{ + bool opened = (module_interface_p () && !module_partition_p () + && import->is_partition ()); + if (opened) + open (loc); + return opened; +} + +/* Open a new linemap interval. The just-created ordinary map is the + first map of the interval. */ + +void +loc_spans::open (location_t hwm = UNKNOWN_LOCATION) +{ + if (hwm == UNKNOWN_LOCATION) + hwm = MAP_START_LOCATION (LINEMAPS_LAST_ORDINARY_MAP (line_table)); + + span interval; + interval.ordinary.first = interval.ordinary.second = hwm; + interval.macro.first = interval.macro.second + = LINEMAPS_MACRO_LOWEST_LOCATION (line_table); + interval.ordinary_delta = interval.macro_delta = 0; + dump (dumper::LOCATION) + && dump ("Opening span %u ordinary:[%u,... macro:...,%u)", + spans->length (), interval.ordinary.first, + interval.macro.second); + spans->safe_push (interval); +} + +/* Close out the current linemap interval. The last maps are within + the interval. */ + +void +loc_spans::close () +{ + span &interval = spans->last (); + + interval.ordinary.second + = ((line_table->highest_location + (1 << line_table->default_range_bits)) + & ~((1u << line_table->default_range_bits) - 1)); + interval.macro.first = LINEMAPS_MACRO_LOWEST_LOCATION (line_table); + dump (dumper::LOCATION) + && dump ("Closing span %u ordinary:[%u,%u) macro:[%u,%u)", + spans->length () - 1, + interval.ordinary.first,interval.ordinary.second, + interval.macro.first, interval.macro.second); +} + +/* Given an ordinary location LOC, return the lmap_interval it resides + in. NULL if it is not in an interval. */ + +const loc_spans::span * +loc_spans::ordinary (location_t loc) +{ + unsigned len = spans->length (); + unsigned pos = 0; + while (len) + { + unsigned half = len / 2; + const span &probe = (*spans)[pos + half]; + if (loc < probe.ordinary.first) + len = half; + else if (loc < probe.ordinary.second) + return &probe; + else + { + pos += half + 1; + len = len - (half + 1); + } + } + return NULL; +} + +/* Likewise, given a macro location LOC, return the lmap interval it + resides in. */ + +const loc_spans::span * +loc_spans::macro (location_t loc) +{ + unsigned len = spans->length (); + unsigned pos = 0; + while (len) + { + unsigned half = len / 2; + const span &probe = (*spans)[pos + half]; + if (loc >= probe.macro.second) + len = half; + else if (loc >= probe.macro.first) + return &probe; + else + { + pos += half + 1; + len = len - (half + 1); + } + } + return NULL; +} + +/* Return the ordinary location closest to FROM. */ + +static location_t +ordinary_loc_of (line_maps *lmaps, location_t from) +{ + while (!IS_ORDINARY_LOC (from)) + { + if (IS_ADHOC_LOC (from)) + from = get_location_from_adhoc_loc (lmaps, from); + if (IS_MACRO_LOC (from)) + { + /* Find the ordinary location nearest FROM. */ + const line_map *map = linemap_lookup (lmaps, from); + const line_map_macro *mac_map = linemap_check_macro (map); + from = MACRO_MAP_EXPANSION_POINT_LOCATION (mac_map); + } + } + return from; +} + +static module_state ** +get_module_slot (tree name, module_state *parent, bool partition, bool insert) +{ + module_state_hash::compare_type ct (name, uintptr_t (parent) | partition); + hashval_t hv = module_state_hash::hash (ct); + + return modules_hash->find_slot_with_hash (ct, hv, insert ? INSERT : NO_INSERT); +} + +static module_state * +get_primary (module_state *parent) +{ + while (parent->is_partition ()) + parent = parent->parent; + + if (!parent->name) + // Implementation unit has null name + parent = parent->parent; + + return parent; +} + +/* Find or create module NAME & PARENT in the hash table. */ + +module_state * +get_module (tree name, module_state *parent, bool partition) +{ + if (partition) + { + if (!parent) + parent = get_primary ((*modules)[0]); + + if (!parent->is_partition () && !parent->flatname) + parent->set_flatname (); + } + + module_state **slot = get_module_slot (name, parent, partition, true); + module_state *state = *slot; + if (!state) + { + state = (new (ggc_alloc<module_state> ()) + module_state (name, parent, partition)); + *slot = state; + } + return state; +} + +/* Process string name PTR into a module_state. */ + +static module_state * +get_module (const char *ptr) +{ + if (ptr[0] == '.' ? IS_DIR_SEPARATOR (ptr[1]) : IS_ABSOLUTE_PATH (ptr)) + /* A header name. */ + return get_module (build_string (strlen (ptr), ptr)); + + bool partition = false; + module_state *mod = NULL; + + for (const char *probe = ptr;; probe++) + if (!*probe || *probe == '.' || *probe == ':') + { + if (probe == ptr) + return NULL; + + mod = get_module (get_identifier_with_length (ptr, probe - ptr), + mod, partition); + ptr = probe; + if (*ptr == ':') + { + if (partition) + return NULL; + partition = true; + } + + if (!*ptr++) + break; + } + else if (!(ISALPHA (*probe) || *probe == '_' + || (probe != ptr && ISDIGIT (*probe)))) + return NULL; + + return mod; +} + +/* Create a new mapper connecting to OPTION. */ + +module_client * +make_mapper (location_t loc) +{ + timevar_start (TV_MODULE_MAPPER); + const char *option = module_mapper_name; + if (!option) + option = getenv ("CXX_MODULE_MAPPER"); + + mapper = module_client::open_module_client + (loc, option, &set_cmi_repo, + (save_decoded_options[0].opt_index == OPT_SPECIAL_program_name) + && save_decoded_options[0].arg != progname + ? save_decoded_options[0].arg : nullptr); + + timevar_stop (TV_MODULE_MAPPER); + + return mapper; +} + +/* If THIS is the current purview, issue an import error and return false. */ + +bool +module_state::check_not_purview (location_t from) +{ + module_state *imp = (*modules)[0]; + if (imp && !imp->name) + imp = imp->parent; + if (imp == this) + { + /* Cannot import the current module. */ + error_at (from, "cannot import module in its own purview"); + inform (loc, "module %qs declared here", get_flatname ()); + return false; + } + return true; +} + +/* Module name substitutions. */ +static vec<module_state *,va_heap> substs; + +void +module_state::mangle (bool include_partition) +{ + if (subst) + mangle_module_substitution (subst - 1); + else + { + if (parent) + parent->mangle (include_partition); + if (include_partition || !is_partition ()) + { + char p = 0; + // Partitions are significant for global initializer functions + if (is_partition () && !parent->is_partition ()) + p = 'P'; + substs.safe_push (this); + subst = substs.length (); + mangle_identifier (p, name); + } + } +} + +void +mangle_module (int mod, bool include_partition) +{ + module_state *imp = (*modules)[mod]; + + if (!imp->name) + /* Set when importing the primary module interface. */ + imp = imp->parent; + + imp->mangle (include_partition); +} + +/* Clean up substitutions. */ +void +mangle_module_fini () +{ + while (substs.length ()) + substs.pop ()->subst = 0; +} + +/* Announce WHAT about the module. */ + +void +module_state::announce (const char *what) const +{ + if (noisy_p ()) + { + fprintf (stderr, " %s:%s", what, get_flatname ()); + fflush (stderr); + } +} + +/* A human-readable README section. The contents of this section to + not contribute to the CRC, so the contents can change per + compilation. That allows us to embed CWD, hostname, build time and + what not. It is a STRTAB that may be extracted with: + readelf -pgnu.c++.README $(module).gcm */ + +void +module_state::write_readme (elf_out *to, cpp_reader *reader, + const char *dialect, unsigned extensions) +{ + bytes_out readme (to); + + readme.begin (false); + + readme.printf ("GNU C++ %smodule%s%s", + is_header () ? "header " : is_partition () ? "" : "primary ", + is_header () ? "" + : is_interface () ? " interface" : " implementation", + is_partition () ? " partition" : ""); + + /* Compiler's version. */ + readme.printf ("compiler: %s", version_string); + + /* Module format version. */ + verstr_t string; + version2string (MODULE_VERSION, string); + readme.printf ("version: %s", string); + + /* Module information. */ + readme.printf ("module: %s", get_flatname ()); + readme.printf ("source: %s", main_input_filename); + readme.printf ("dialect: %s", dialect); + if (extensions) + readme.printf ("extensions: %s", + extensions & SE_OPENMP ? "-fopenmp" : ""); + + /* The following fields could be expected to change between + otherwise identical compilations. Consider a distributed build + system. We should have a way of overriding that. */ + if (char *cwd = getcwd (NULL, 0)) + { + readme.printf ("cwd: %s", cwd); + free (cwd); + } + readme.printf ("repository: %s", cmi_repo ? cmi_repo : "."); +#if NETWORKING + { + char hostname[64]; + if (!gethostname (hostname, sizeof (hostname))) + readme.printf ("host: %s", hostname); + } +#endif + { + /* This of course will change! */ + time_t stampy; + auto kind = cpp_get_date (reader, &stampy); + if (kind != CPP_time_kind::UNKNOWN) + { + struct tm *time; + + time = gmtime (&stampy); + readme.print_time ("build", time, "UTC"); + + if (kind == CPP_time_kind::DYNAMIC) + { + time = localtime (&stampy); + readme.print_time ("local", time, +#if defined (__USE_MISC) || defined (__USE_BSD) /* Is there a better way? */ + time->tm_zone +#else + "" +#endif + ); + } + } + } + + /* Its direct imports. */ + for (unsigned ix = 1; ix < modules->length (); ix++) + { + module_state *state = (*modules)[ix]; + + if (state->is_direct ()) + readme.printf ("%s: %s %s", state->exported_p ? "export" : "import", + state->get_flatname (), state->filename); + } + + readme.end (to, to->name (MOD_SNAME_PFX ".README"), NULL); +} + +/* Sort environment var names in reverse order. */ + +static int +env_var_cmp (const void *a_, const void *b_) +{ + const unsigned char *a = *(const unsigned char *const *)a_; + const unsigned char *b = *(const unsigned char *const *)b_; + + for (unsigned ix = 0; ; ix++) + { + bool a_end = !a[ix] || a[ix] == '='; + if (a[ix] == b[ix]) + { + if (a_end) + break; + } + else + { + bool b_end = !b[ix] || b[ix] == '='; + + if (!a_end && !b_end) + return a[ix] < b[ix] ? +1 : -1; + if (a_end && b_end) + break; + return a_end ? +1 : -1; + } + } + + return 0; +} + +/* Write the environment. It is a STRTAB that may be extracted with: + readelf -pgnu.c++.ENV $(module).gcm */ + +void +module_state::write_env (elf_out *to) +{ + vec<const char *> vars; + vars.create (20); + + extern char **environ; + while (const char *var = environ[vars.length ()]) + vars.safe_push (var); + vars.qsort (env_var_cmp); + + bytes_out env (to); + env.begin (false); + while (vars.length ()) + env.printf ("%s", vars.pop ()); + env.end (to, to->name (MOD_SNAME_PFX ".ENV"), NULL); + + vars.release (); +} + +/* Write the direct or indirect imports. + u:N + { + u:index + s:name + u32:crc + s:filename (direct) + u:exported (direct) + } imports[N] + */ + +void +module_state::write_imports (bytes_out &sec, bool direct) +{ + unsigned count = 0; + + for (unsigned ix = 1; ix < modules->length (); ix++) + { + module_state *imp = (*modules)[ix]; + + if (imp->remap && imp->is_direct () == direct) + count++; + } + + gcc_assert (!direct || count); + + sec.u (count); + for (unsigned ix = 1; ix < modules->length (); ix++) + { + module_state *imp = (*modules)[ix]; + + if (imp->remap && imp->is_direct () == direct) + { + dump () && dump ("Writing %simport:%u->%u %M (crc=%x)", + !direct ? "indirect " + : imp->exported_p ? "exported " : "", + ix, imp->remap, imp, imp->crc); + sec.u (imp->remap); + sec.str (imp->get_flatname ()); + sec.u32 (imp->crc); + if (direct) + { + write_location (sec, imp->imported_from ()); + sec.str (imp->filename); + int exportedness = 0; + if (imp->exported_p) + exportedness = +1; + else if (!imp->is_purview_direct ()) + exportedness = -1; + sec.i (exportedness); + } + } + } +} + +/* READER, LMAPS != NULL == direct imports, + == NUL == indirect imports. */ + +unsigned +module_state::read_imports (bytes_in &sec, cpp_reader *reader, line_maps *lmaps) +{ + unsigned count = sec.u (); + unsigned loaded = 0; + + while (count--) + { + unsigned ix = sec.u (); + if (ix >= slurp->remap->length () || !ix || (*slurp->remap)[ix]) + { + sec.set_overrun (); + break; + } + + const char *name = sec.str (NULL); + module_state *imp = get_module (name); + unsigned crc = sec.u32 (); + int exportedness = 0; + + /* If the import is a partition, it must be the same primary + module as this TU. */ + if (imp && imp->is_partition () && + (!named_module_p () + || (get_primary ((*modules)[0]) != get_primary (imp)))) + imp = NULL; + + if (!imp) + sec.set_overrun (); + if (sec.get_overrun ()) + break; + + if (lmaps) + { + /* A direct import, maybe load it. */ + location_t floc = read_location (sec); + const char *fname = sec.str (NULL); + exportedness = sec.i (); + + if (sec.get_overrun ()) + break; + + if (!imp->check_not_purview (loc)) + continue; + + if (imp->loadedness == ML_NONE) + { + imp->loc = floc; + imp->crc = crc; + if (!imp->get_flatname ()) + imp->set_flatname (); + + unsigned n = dump.push (imp); + + if (!imp->filename && fname) + imp->filename = xstrdup (fname); + + if (imp->is_partition ()) + dump () && dump ("Importing elided partition %M", imp); + + if (!imp->do_import (reader, false)) + imp = NULL; + dump.pop (n); + if (!imp) + continue; + } + + if (is_partition ()) + { + if (!imp->is_direct ()) + imp->directness = MD_PARTITION_DIRECT; + if (exportedness > 0) + imp->exported_p = true; + } + } + else + { + /* An indirect import, find it, it should already be here. */ + if (imp->loadedness == ML_NONE) + { + error_at (loc, "indirect import %qs is not already loaded", name); + continue; + } + } + + if (imp->crc != crc) + error_at (loc, "import %qs has CRC mismatch", imp->get_flatname ()); + + (*slurp->remap)[ix] = (imp->mod << 1) | (lmaps != NULL); + + if (lmaps && exportedness >= 0) + set_import (imp, bool (exportedness)); + dump () && dump ("Found %simport:%u %M->%u", !lmaps ? "indirect " + : exportedness > 0 ? "exported " + : exportedness < 0 ? "gmf" : "", ix, imp, + imp->mod); + loaded++; + } + + return loaded; +} + +/* Write the import table to MOD_SNAME_PFX.imp. */ + +void +module_state::write_imports (elf_out *to, unsigned *crc_ptr) +{ + dump () && dump ("Writing imports"); + dump.indent (); + + bytes_out sec (to); + sec.begin (); + + write_imports (sec, true); + write_imports (sec, false); + + sec.end (to, to->name (MOD_SNAME_PFX ".imp"), crc_ptr); + dump.outdent (); +} + +bool +module_state::read_imports (cpp_reader *reader, line_maps *lmaps) +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".imp")) + return false; + + dump () && dump ("Reading %u imports", slurp->remap->length () - 1); + dump.indent (); + + /* Read the imports. */ + unsigned direct = read_imports (sec, reader, lmaps); + unsigned indirect = read_imports (sec, NULL, NULL); + if (direct + indirect + 1 != slurp->remap->length ()) + from ()->set_error (elf::E_BAD_IMPORT); + + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* We're the primary module interface, but have partitions. Document + them so that non-partition module implementation units know which + have already been loaded. */ + +void +module_state::write_partitions (elf_out *to, unsigned count, unsigned *crc_ptr) +{ + dump () && dump ("Writing %u elided partitions", count); + dump.indent (); + + bytes_out sec (to); + sec.begin (); + + for (unsigned ix = 1; ix != modules->length (); ix++) + { + module_state *imp = (*modules)[ix]; + if (imp->is_partition ()) + { + dump () && dump ("Writing elided partition %M (crc=%x)", + imp, imp->crc); + sec.str (imp->get_flatname ()); + sec.u32 (imp->crc); + write_location (sec, imp->is_direct () + ? imp->imported_from () : UNKNOWN_LOCATION); + sec.str (imp->filename); + } + } + + sec.end (to, to->name (MOD_SNAME_PFX ".prt"), crc_ptr); + dump.outdent (); +} + +bool +module_state::read_partitions (unsigned count) +{ + bytes_in sec; + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".prt")) + return false; + + dump () && dump ("Reading %u elided partitions", count); + dump.indent (); + + while (count--) + { + const char *name = sec.str (NULL); + unsigned crc = sec.u32 (); + location_t floc = read_location (sec); + const char *fname = sec.str (NULL); + + if (sec.get_overrun ()) + break; + + dump () && dump ("Reading elided partition %s (crc=%x)", name, crc); + + module_state *imp = get_module (name); + if (!imp || !imp->is_partition () || imp->is_rooted () + || get_primary (imp) != this) + { + sec.set_overrun (); + break; + } + + /* Attach the partition without loading it. We'll have to load + for real if it's indirectly imported. */ + imp->loc = floc; + imp->crc = crc; + if (!imp->filename && fname[0]) + imp->filename = xstrdup (fname); + } + + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* Counter indices. */ +enum module_state_counts +{ + MSC_sec_lwm, + MSC_sec_hwm, + MSC_pendings, + MSC_entities, + MSC_namespaces, + MSC_bindings, + MSC_macros, + MSC_inits, + MSC_HWM +}; + +/* Data for config reading and writing. */ +struct module_state_config { + const char *dialect_str; + unsigned num_imports; + unsigned num_partitions; + unsigned num_entities; + unsigned ordinary_locs; + unsigned macro_locs; + unsigned ordinary_loc_align; + +public: + module_state_config () + :dialect_str (get_dialect ()), + num_imports (0), num_partitions (0), num_entities (0), + ordinary_locs (0), macro_locs (0), ordinary_loc_align (0) + { + } + + static void release () + { + XDELETEVEC (dialect); + dialect = NULL; + } + +private: + static const char *get_dialect (); + static char *dialect; +}; + +char *module_state_config::dialect; + +/* Generate a string of the significant compilation options. + Generally assume the user knows what they're doing, in the same way + that object files can be mixed. */ + +const char * +module_state_config::get_dialect () +{ + if (!dialect) + dialect = concat (get_cxx_dialect_name (cxx_dialect), + /* C++ implies these, only show if disabled. */ + flag_exceptions ? "" : "/no-exceptions", + flag_rtti ? "" : "/no-rtti", + flag_new_inheriting_ctors ? "" : "/old-inheriting-ctors", + /* C++ 20 implies concepts. */ + cxx_dialect < cxx20 && flag_concepts ? "/concepts" : "", + flag_coroutines ? "/coroutines" : "", + flag_module_implicit_inline ? "/implicit-inline" : "", + NULL); + + return dialect; +} + +/* Contents of a cluster. */ +enum cluster_tag { + ct_decl, /* A decl. */ + ct_defn, /* A definition. */ + ct_bind, /* A binding. */ + ct_hwm +}; + +/* Binding modifiers. */ +enum ct_bind_flags +{ + cbf_export = 0x1, /* An exported decl. */ + cbf_hidden = 0x2, /* A hidden (friend) decl. */ + cbf_using = 0x4, /* A using decl. */ + cbf_wrapped = 0x8, /* ... that is wrapped. */ +}; + +/* Write the cluster of depsets in SCC[0-SIZE). */ + +unsigned +module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, + depset::hash &table, unsigned *counts, + unsigned *crc_ptr) +{ + dump () && dump ("Writing section:%u %u depsets", table.section, size); + dump.indent (); + + trees_out sec (to, this, table, table.section); + sec.begin (); + + /* Determine entity numbers, mark for writing. */ + dump (dumper::CLUSTER) && dump ("Cluster members:") && (dump.indent (), true); + for (unsigned ix = 0; ix != size; ix++) + { + depset *b = scc[ix]; + + switch (b->get_entity_kind ()) + { + default: + gcc_unreachable (); + + case depset::EK_BINDING: + dump (dumper::CLUSTER) + && dump ("[%u]=%s %P", ix, b->entity_kind_name (), + b->get_entity (), b->get_name ()); + for (unsigned jx = b->deps.length (); jx--;) + { + depset *dep = b->deps[jx]; + if (jx) + gcc_checking_assert (dep->get_entity_kind () == depset::EK_USING + || TREE_VISITED (dep->get_entity ())); + else + gcc_checking_assert (dep->get_entity_kind () + == depset::EK_NAMESPACE + && dep->get_entity () == b->get_entity ()); + } + break; + + case depset::EK_DECL: + if (b->is_member ()) + { + case depset::EK_SPECIALIZATION: /* Yowzer! */ + case depset::EK_PARTIAL: /* Hey, let's do it again! */ + counts[MSC_pendings]++; + } + b->cluster = counts[MSC_entities]++; + sec.mark_declaration (b->get_entity (), b->has_defn ()); + /* FALLTHROUGH */ + + case depset::EK_USING: + gcc_checking_assert (!b->is_import () + && !b->is_unreached ()); + dump (dumper::CLUSTER) + && dump ("[%u]=%s %s %N", ix, b->entity_kind_name (), + b->has_defn () ? "definition" : "declaration", + b->get_entity ()); + break; + } + } + dump (dumper::CLUSTER) && (dump.outdent (), true); + + /* Ensure every imported decl is referenced before we start + streaming. This ensures that we never encounter the + situation where this cluster instantiates some implicit + member that importing some other decl causes to be + instantiated. */ + sec.set_importing (+1); + for (unsigned ix = 0; ix != size; ix++) + { + depset *b = scc[ix]; + for (unsigned jx = (b->get_entity_kind () == depset::EK_BINDING + || b->is_special ()) ? 1 : 0; + jx != b->deps.length (); jx++) + { + depset *dep = b->deps[jx]; + + if (!dep->is_binding () + && dep->is_import () && !TREE_VISITED (dep->get_entity ())) + { + tree import = dep->get_entity (); + + sec.tree_node (import); + dump (dumper::CLUSTER) && dump ("Seeded import %N", import); + } + } + } + sec.tree_node (NULL_TREE); + /* We're done importing now. */ + sec.set_importing (-1); + + /* Write non-definitions. */ + for (unsigned ix = 0; ix != size; ix++) + { + depset *b = scc[ix]; + tree decl = b->get_entity (); + switch (b->get_entity_kind ()) + { + default: + gcc_unreachable (); + break; + + case depset::EK_BINDING: + { + gcc_assert (TREE_CODE (decl) == NAMESPACE_DECL); + dump () && dump ("Depset:%u binding %C:%P", ix, TREE_CODE (decl), + decl, b->get_name ()); + sec.u (ct_bind); + sec.tree_node (decl); + sec.tree_node (b->get_name ()); + + /* Write in reverse order, so reading will see the exports + first, thus building the overload chain will be + optimized. */ + for (unsigned jx = b->deps.length (); --jx;) + { + depset *dep = b->deps[jx]; + tree bound = dep->get_entity (); + unsigned flags = 0; + if (dep->get_entity_kind () == depset::EK_USING) + { + tree ovl = bound; + bound = OVL_FUNCTION (bound); + if (!(TREE_CODE (bound) == CONST_DECL + && UNSCOPED_ENUM_P (TREE_TYPE (bound)) + && decl == TYPE_NAME (TREE_TYPE (bound)))) + { + /* An unscope enumerator in its enumeration's + scope is not a using. */ + flags |= cbf_using; + if (OVL_USING_P (ovl)) + flags |= cbf_wrapped; + } + if (OVL_EXPORT_P (ovl)) + flags |= cbf_export; + } + else + { + /* An implicit typedef must be at one. */ + gcc_assert (!DECL_IMPLICIT_TYPEDEF_P (bound) || jx == 1); + if (dep->is_hidden ()) + flags |= cbf_hidden; + else if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (bound))) + flags |= cbf_export; + } + + gcc_checking_assert (DECL_P (bound)); + + sec.i (flags); + sec.tree_node (bound); + } + + /* Terminate the list. */ + sec.i (-1); + } + break; + + case depset::EK_USING: + dump () && dump ("Depset:%u %s %C:%N", ix, b->entity_kind_name (), + TREE_CODE (decl), decl); + break; + + case depset::EK_SPECIALIZATION: + case depset::EK_PARTIAL: + case depset::EK_DECL: + dump () && dump ("Depset:%u %s entity:%u %C:%N", ix, + b->entity_kind_name (), b->cluster, + TREE_CODE (decl), decl); + + sec.u (ct_decl); + sec.tree_node (decl); + + dump () && dump ("Wrote declaration entity:%u %C:%N", + b->cluster, TREE_CODE (decl), decl); + break; + } + } + + depset *namer = NULL; + + /* Write out definitions */ + for (unsigned ix = 0; ix != size; ix++) + { + depset *b = scc[ix]; + tree decl = b->get_entity (); + switch (b->get_entity_kind ()) + { + default: + break; + + case depset::EK_SPECIALIZATION: + case depset::EK_PARTIAL: + case depset::EK_DECL: + if (!namer) + namer = b; + + if (b->has_defn ()) + { + sec.u (ct_defn); + sec.tree_node (decl); + dump () && dump ("Writing definition %N", decl); + sec.write_definition (decl); + + if (!namer->has_defn ()) + namer = b; + } + break; + } + } + + /* We don't find the section by name. Use depset's decl's name for + human friendliness. */ + unsigned name = 0; + tree naming_decl = NULL_TREE; + if (namer) + { + naming_decl = namer->get_entity (); + if (namer->get_entity_kind () == depset::EK_USING) + /* This unfortunately names the section from the target of the + using decl. But the name is only a guide, so Do Not Care. */ + naming_decl = OVL_FUNCTION (naming_decl); + if (DECL_IMPLICIT_TYPEDEF_P (naming_decl)) + /* Lose any anonymousness. */ + naming_decl = TYPE_NAME (TREE_TYPE (naming_decl)); + name = to->qualified_name (naming_decl, namer->has_defn ()); + } + + unsigned bytes = sec.pos; + unsigned snum = sec.end (to, name, crc_ptr); + + for (unsigned ix = size; ix--;) + gcc_checking_assert (scc[ix]->section == snum); + + dump.outdent (); + dump () && dump ("Wrote section:%u named-by:%N", table.section, naming_decl); + + return bytes; +} + +/* Read a cluster from section SNUM. */ + +bool +module_state::read_cluster (unsigned snum) +{ + trees_in sec (this); + + if (!sec.begin (loc, from (), snum)) + return false; + + dump () && dump ("Reading section:%u", snum); + dump.indent (); + + /* We care about structural equality. */ + comparing_dependent_aliases++; + + /* First seed the imports. */ + while (tree import = sec.tree_node ()) + dump (dumper::CLUSTER) && dump ("Seeded import %N", import); + + while (!sec.get_overrun () && sec.more_p ()) + { + unsigned ct = sec.u (); + switch (ct) + { + default: + sec.set_overrun (); + break; + + case ct_bind: + /* A set of namespace bindings. */ + { + tree ns = sec.tree_node (); + tree name = sec.tree_node (); + tree decls = NULL_TREE; + tree visible = NULL_TREE; + tree type = NULL_TREE; + bool dedup = false; + + /* We rely on the bindings being in the reverse order of + the resulting overload set. */ + for (;;) + { + int flags = sec.i (); + if (flags < 0) + break; + + if ((flags & cbf_hidden) + && (flags & (cbf_using | cbf_export))) + sec.set_overrun (); + + tree decl = sec.tree_node (); + if (sec.get_overrun ()) + break; + + if (decls && TREE_CODE (decl) == TYPE_DECL) + { + /* Stat hack. */ + if (type || !DECL_IMPLICIT_TYPEDEF_P (decl)) + sec.set_overrun (); + type = decl; + } + else + { + if (decls + || (flags & (cbf_hidden | cbf_wrapped)) + || DECL_FUNCTION_TEMPLATE_P (decl)) + { + decls = ovl_make (decl, decls); + if (flags & cbf_using) + { + dedup = true; + OVL_USING_P (decls) = true; + if (flags & cbf_export) + OVL_EXPORT_P (decls) = true; + } + + if (flags & cbf_hidden) + OVL_HIDDEN_P (decls) = true; + else if (dedup) + OVL_DEDUP_P (decls) = true; + } + else + decls = decl; + + if (flags & cbf_export + || (!(flags & cbf_hidden) + && (is_module () || is_partition ()))) + visible = decls; + } + } + + if (!decls) + sec.set_overrun (); + + if (sec.get_overrun ()) + break; /* Bail. */ + + dump () && dump ("Binding of %P", ns, name); + if (!set_module_binding (ns, name, mod, + is_header () ? -1 + : is_module () || is_partition () ? 1 + : 0, + decls, type, visible)) + sec.set_overrun (); + + if (type + && CP_DECL_CONTEXT (type) == ns + && !sec.is_duplicate (type)) + add_module_decl (ns, name, type); + + for (ovl_iterator iter (decls); iter; ++iter) + if (!iter.using_p ()) + { + tree decl = *iter; + if (CP_DECL_CONTEXT (decl) == ns + && !sec.is_duplicate (decl)) + add_module_decl (ns, name, decl); + } + } + break; + + case ct_decl: + /* A decl. */ + { + tree decl = sec.tree_node (); + dump () && dump ("Read declaration of %N", decl); + } + break; + + case ct_defn: + { + tree decl = sec.tree_node (); + dump () && dump ("Reading definition of %N", decl); + sec.read_definition (decl); + } + break; + } + } + + /* When lazy loading is in effect, we can be in the middle of + parsing or instantiating a function. Save it away. + push_function_context does too much work. */ + tree old_cfd = current_function_decl; + struct function *old_cfun = cfun; + while (tree decl = sec.post_process ()) + { + bool abstract = false; + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + abstract = true; + decl = DECL_TEMPLATE_RESULT (decl); + } + + current_function_decl = decl; + allocate_struct_function (decl, abstract); + cfun->language = ggc_cleared_alloc<language_function> (); + cfun->language->base.x_stmt_tree.stmts_are_full_exprs_p = 1; + + if (abstract) + ; + else if (DECL_ABSTRACT_P (decl)) + { + bool cloned = maybe_clone_body (decl); + if (!cloned) + from ()->set_error (); + } + else + { + bool aggr = aggregate_value_p (DECL_RESULT (decl), decl); +#ifdef PCC_STATIC_STRUCT_RETURN + cfun->returns_pcc_struct = aggr; +#endif + cfun->returns_struct = aggr; + + if (DECL_COMDAT (decl)) + // FIXME: Comdat grouping? + comdat_linkage (decl); + note_vague_linkage_fn (decl); + cgraph_node::finalize_function (decl, true); + } + + } + /* Look, function.c's interface to cfun does too much for us, we + just need to restore the old value. I do not want to go + redesigning that API right now. */ +#undef cfun + cfun = old_cfun; + current_function_decl = old_cfd; + comparing_dependent_aliases--; + + dump.outdent (); + dump () && dump ("Read section:%u", snum); + + loaded_clusters++; + + if (!sec.end (from ())) + return false; + + return true; +} + +void +module_state::write_namespace (bytes_out &sec, depset *dep) +{ + unsigned ns_num = dep->cluster; + unsigned ns_import = 0; + + if (dep->is_import ()) + ns_import = dep->section; + else if (dep->get_entity () != global_namespace) + ns_num++; + + sec.u (ns_import); + sec.u (ns_num); +} + +tree +module_state::read_namespace (bytes_in &sec) +{ + unsigned ns_import = sec.u (); + unsigned ns_num = sec.u (); + tree ns = NULL_TREE; + + if (ns_import || ns_num) + { + if (!ns_import) + ns_num--; + + if (unsigned origin = slurp->remap_module (ns_import)) + { + module_state *from = (*modules)[origin]; + if (ns_num < from->entity_num) + { + binding_slot &slot = (*entity_ary)[from->entity_lwm + ns_num]; + + if (!slot.is_lazy ()) + ns = slot; + } + } + else + sec.set_overrun (); + } + else + ns = global_namespace; + + return ns; +} + +/* SPACES is a sorted vector of namespaces. Write out the namespaces + to MOD_SNAME_PFX.nms section. */ + +void +module_state::write_namespaces (elf_out *to, vec<depset *> spaces, + unsigned num, unsigned *crc_p) +{ + dump () && dump ("Writing namespaces"); + dump.indent (); + + bytes_out sec (to); + sec.begin (); + + for (unsigned ix = 0; ix != num; ix++) + { + depset *b = spaces[ix]; + tree ns = b->get_entity (); + + gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL); + + bool export_p = DECL_MODULE_EXPORT_P (ns); + bool inline_p = DECL_NAMESPACE_INLINE_P (ns); + bool public_p = TREE_PUBLIC (ns); + + /* We should only be naming public namespaces, or our own + private ones. Internal linkage ones never get to be written + out -- because that means something erroneously referred to a + member. However, Davis Herring's paper probably changes that + by permitting them to be written out, but then an error if on + touches them. (Certain cases cannot be detected until that + point.) */ + gcc_checking_assert (public_p || !DECL_MODULE_IMPORT_P (ns)); + unsigned flags = 0; + if (export_p) + flags |= 1; + if (inline_p) + flags |= 2; + if (public_p) + flags |= 4; + dump () && dump ("Writing namespace:%u %N%s%s%s", + b->cluster, ns, export_p ? ", export" : "", + public_p ? ", public" : "", + inline_p ? ", inline" : ""); + sec.u (b->cluster); + sec.u (to->name (DECL_NAME (ns))); + write_namespace (sec, b->deps[0]); + + /* Don't use bools, because this can be near the end of the + section, and it won't save anything anyway. */ + sec.u (flags); + write_location (sec, DECL_SOURCE_LOCATION (ns)); + } + + sec.end (to, to->name (MOD_SNAME_PFX ".nms"), crc_p); + dump.outdent (); +} + +/* Read the namespace hierarchy from MOD_SNAME_PFX.namespace. Fill in + SPACES from that data. */ + +bool +module_state::read_namespaces (unsigned num) +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".nms")) + return false; + + dump () && dump ("Reading namespaces"); + dump.indent (); + + for (unsigned ix = 0; ix != num; ix++) + { + unsigned entity_index = sec.u (); + unsigned name = sec.u (); + + tree parent = read_namespace (sec); + + /* See comment in write_namespace about why not bits. */ + unsigned flags = sec.u (); + location_t src_loc = read_location (sec); + + if (entity_index >= entity_num || !parent) + sec.set_overrun (); + if (sec.get_overrun ()) + break; + + tree id = name ? get_identifier (from ()->name (name)) : NULL_TREE; + bool public_p = flags & 4; + bool inline_p = flags & 2; + bool export_p = flags & 1; + + dump () && dump ("Read namespace:%u %P%s%s%s", + entity_index, parent, id, export_p ? ", export" : "", + public_p ? ", public" : "", + inline_p ? ", inline" : ""); + bool visible_p = (export_p + || (public_p && (is_partition () || is_module ()))); + tree inner = add_imported_namespace (parent, id, mod, + src_loc, visible_p, inline_p); + if (export_p && is_partition ()) + DECL_MODULE_EXPORT_P (inner) = true; + + /* Install the namespace. */ + (*entity_ary)[entity_lwm + entity_index] = inner; + if (DECL_MODULE_IMPORT_P (inner)) + { + bool existed; + unsigned *slot = &entity_map->get_or_insert + (DECL_UID (inner), &existed); + if (existed) + /* If it existed, it should match. */ + gcc_checking_assert (inner == (*entity_ary)[*slot]); + else + *slot = entity_lwm + entity_index; + } + } + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* Write the binding TABLE to MOD_SNAME_PFX.bnd */ + +unsigned +module_state::write_bindings (elf_out *to, vec<depset *> sccs, unsigned *crc_p) +{ + dump () && dump ("Writing binding table"); + dump.indent (); + + unsigned num = 0; + bytes_out sec (to); + sec.begin (); + + for (unsigned ix = 0; ix != sccs.length (); ix++) + { + depset *b = sccs[ix]; + if (b->is_binding ()) + { + tree ns = b->get_entity (); + dump () && dump ("Bindings %P section:%u", ns, b->get_name (), + b->section); + sec.u (to->name (b->get_name ())); + write_namespace (sec, b->deps[0]); + sec.u (b->section); + num++; + } + } + + sec.end (to, to->name (MOD_SNAME_PFX ".bnd"), crc_p); + dump.outdent (); + + return num; +} + +/* Read the binding table from MOD_SNAME_PFX.bind. */ + +bool +module_state::read_bindings (unsigned num, unsigned lwm, unsigned hwm) +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".bnd")) + return false; + + dump () && dump ("Reading binding table"); + dump.indent (); + for (; !sec.get_overrun () && num--;) + { + const char *name = from ()->name (sec.u ()); + tree ns = read_namespace (sec); + unsigned snum = sec.u (); + + if (!ns || !name || (snum - lwm) >= (hwm - lwm)) + sec.set_overrun (); + if (!sec.get_overrun ()) + { + tree id = get_identifier (name); + dump () && dump ("Bindings %P section:%u", ns, id, snum); + if (mod && !import_module_binding (ns, id, mod, snum)) + break; + } + } + + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* Write the entity table to MOD_SNAME_PFX.ent + + Each entry is a section number. */ + +void +module_state::write_entities (elf_out *to, vec<depset *> depsets, + unsigned count, unsigned *crc_p) +{ + dump () && dump ("Writing entities"); + dump.indent (); + + bytes_out sec (to); + sec.begin (); + + unsigned current = 0; + for (unsigned ix = 0; ix < depsets.length (); ix++) + { + depset *d = depsets[ix]; + + switch (d->get_entity_kind ()) + { + default: + break; + + case depset::EK_NAMESPACE: + if (!d->is_import () && d->get_entity () != global_namespace) + { + gcc_checking_assert (d->cluster == current); + current++; + sec.u (0); + } + break; + + case depset::EK_DECL: + case depset::EK_SPECIALIZATION: + case depset::EK_PARTIAL: + gcc_checking_assert (!d->is_unreached () + && !d->is_import () + && d->cluster == current + && d->section); + current++; + sec.u (d->section); + break; + } + } + gcc_assert (count == current); + sec.end (to, to->name (MOD_SNAME_PFX ".ent"), crc_p); + dump.outdent (); +} + +bool +module_state::read_entities (unsigned count, unsigned lwm, unsigned hwm) +{ + trees_in sec (this); + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".ent")) + return false; + + dump () && dump ("Reading entities"); + dump.indent (); + + for (binding_slot *slot = entity_ary->begin () + entity_lwm; count--; slot++) + { + unsigned snum = sec.u (); + if (snum && (snum - lwm) >= (hwm - lwm)) + sec.set_overrun (); + if (sec.get_overrun ()) + break; + + if (snum) + slot->set_lazy (snum << 2); + } + + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* Write the pending table to MOD_SNAME_PFX.pnd + + Specializations & partials are keyed to their primary template. + Members are keyed to their context. + + For specializations & partials, primary templates are keyed to the + (namespace name) of their originating decl (because that's the only + handle we have). */ + +void +module_state::write_pendings (elf_out *to, vec<depset *> depsets, + depset::hash &table, + unsigned count, unsigned *crc_p) +{ + dump () && dump ("Writing %u pendings", count); + dump.indent (); + + trees_out sec (to, this, table); + sec.begin (); + + for (unsigned ix = 0; ix < depsets.length (); ix++) + { + depset *d = depsets[ix]; + depset::entity_kind kind = d->get_entity_kind (); + tree key = NULL_TREE; + bool is_spec = false; + + + if (kind == depset::EK_SPECIALIZATION) + { + is_spec = true; + key = reinterpret_cast <spec_entry *> (d->deps[0])->tmpl; + } + else if (kind == depset::EK_PARTIAL) + { + is_spec = true; + key = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d->get_entity ())); + } + else if (kind == depset::EK_DECL && d->is_member ()) + { + tree ctx = DECL_CONTEXT (d->get_entity ()); + key = TYPE_NAME (ctx); + if (tree ti = CLASSTYPE_TEMPLATE_INFO (ctx)) + if (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == key) + key = TI_TEMPLATE (ti); + } + + // FIXME:OPTIMIZATION More than likely when there is one pending + // member, there will be others. All written in the same + // section and keyed to the same class. We only need to record + // one of them. The same is not true for specializations + + if (key) + { + gcc_checking_assert (!d->is_import ()); + + { + /* Key the entity to its key. */ + depset *key_dep = table.find_dependency (key); + if (key_dep->get_entity_kind () == depset::EK_REDIRECT) + key_dep = key_dep->deps[0]; + unsigned key_origin + = key_dep->is_import () ? key_dep->section : 0; + sec.u (key_origin); + sec.u (key_dep->cluster); + sec.u (d->cluster); + dump () && dump ("%s %N entity:%u keyed to %M[%u] %N", + is_spec ? "Specialization" : "Member", + d->get_entity (), + d->cluster, (*modules)[key_origin], + key_dep->cluster, key); + } + + if (is_spec) + { + /* Key the general template to the originating decl. */ + tree origin = get_originating_module_decl (key); + sec.tree_node (CP_DECL_CONTEXT (origin)); + sec.tree_node (DECL_NAME (origin)); + + unsigned origin_ident = import_entity_index (origin); + module_state *origin_from = this; + if (!(origin_ident & ~(~0u>>1))) + origin_from = import_entity_module (origin_ident); + sec.u (origin_from->remap); + } + else + sec.tree_node (NULL); + count--; + } + } + gcc_assert (!count); + sec.end (to, to->name (MOD_SNAME_PFX ".pnd"), crc_p); + dump.outdent (); +} + +bool +module_state::read_pendings (unsigned count) +{ + trees_in sec (this); + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".pnd")) + return false; + + dump () && dump ("Reading %u pendings", count); + dump.indent (); + + for (unsigned ix = 0; ix != count; ix++) + { + unsigned key_origin = slurp->remap_module (sec.u ()); + unsigned key_index = sec.u (); + unsigned ent_index = sec.u (); + module_state *from = (*modules)[key_origin]; + tree ns = sec.tree_node (); + + if (!key_origin + || key_index >= from->entity_num || ent_index >= entity_num + || (ns && TREE_CODE (ns) != NAMESPACE_DECL)) + sec.set_overrun (); + + if (sec.get_overrun ()) + break; + + bool loaded = false; + dump () && dump ("%s keyed to %M[%u] entity:%u", + ns ? "Specialization" : "Member", + from, key_index, ent_index); + unsigned key_ident = from->entity_lwm + key_index; + if (pending_table->add (ns ? key_ident : ~key_ident, + ent_index + entity_lwm)) + { + binding_slot &slot = (*entity_ary)[key_ident]; + if (slot.is_lazy ()) + slot.or_lazy (ns ? 1 : 2); + else + { + tree key = slot; + + loaded = true; + if (ns) + { + if (key && TREE_CODE (key) == TEMPLATE_DECL) + DECL_MODULE_PENDING_SPECIALIZATIONS_P (key) = true; + else + sec.set_overrun (); + } + else + { + if (key && TREE_CODE (key) == TYPE_DECL) + DECL_MODULE_PENDING_MEMBERS_P (key) = true; + else + sec.set_overrun (); + } + } + } + + if (ns) + { + /* We also need to mark the namespace binding of the + originating template, so we know to set its pending + specializations flag, when we load it. */ + tree name = sec.tree_node (); + unsigned origin = slurp->remap_module (sec.u ()); + if (!origin || !name || TREE_CODE (name) != IDENTIFIER_NODE) + sec.set_overrun (); + if (sec.get_overrun ()) + break; + + module_state *origin_from = (*modules)[origin]; + if (!loaded + && (origin_from->is_header () + || (origin_from->is_partition () + || origin_from->is_module ()))) + note_pending_specializations (ns, name, origin_from->is_header ()); + } + } + + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +/* Return true if module MOD cares about lazy specializations keyed to + possibly duplicated entity bindings. */ + +bool +lazy_specializations_p (unsigned mod, bool header_p, bool partition_p) +{ + module_state *module = (*modules)[mod]; + + if (module->is_header ()) + return header_p; + + if (module->is_module () || module->is_partition ()) + return partition_p; + + return false; +} + +/* Read & write locations. */ +enum loc_kind { + LK_ORDINARY, + LK_MACRO, + LK_IMPORT_ORDINARY, + LK_IMPORT_MACRO, + LK_ADHOC, + LK_RESERVED, +}; + +static const module_state * +module_for_ordinary_loc (location_t loc) +{ + unsigned pos = 1; + unsigned len = modules->length () - pos; + + while (len) + { + unsigned half = len / 2; + module_state *probe = (*modules)[pos + half]; + if (loc < probe->ordinary_locs.first) + len = half; + else if (loc < probe->ordinary_locs.second) + return probe; + else + { + pos += half + 1; + len = len - (half + 1); + } + } + + return NULL; +} + +static const module_state * +module_for_macro_loc (location_t loc) +{ + unsigned pos = 1; + unsigned len = modules->length () - pos; + + while (len) + { + unsigned half = len / 2; + module_state *probe = (*modules)[pos + half]; + if (loc >= probe->macro_locs.second) + len = half; + else if (loc >= probe->macro_locs.first) + return probe; + else + { + pos += half + 1; + len = len - (half + 1); + } + } + + return NULL; +} + +location_t +module_state::imported_from () const +{ + location_t from = loc; + line_map_ordinary const *fmap + = linemap_check_ordinary (linemap_lookup (line_table, from)); + + if (MAP_MODULE_P (fmap)) + from = linemap_included_from (fmap); + + return from; +} + +/* If we're not streaming, record that we need location LOC. + Otherwise stream it. */ + +void +module_state::write_location (bytes_out &sec, location_t loc) +{ + if (!sec.streaming_p ()) + /* This is where we should note we use this location. See comment + about write_ordinary_maps. */ + return; + + if (loc < RESERVED_LOCATION_COUNT) + { + dump (dumper::LOCATION) && dump ("Reserved location %u", unsigned (loc)); + sec.u (LK_RESERVED + loc); + } + else if (IS_ADHOC_LOC (loc)) + { + dump (dumper::LOCATION) && dump ("Adhoc location"); + sec.u (LK_ADHOC); + location_t locus = get_location_from_adhoc_loc (line_table, loc); + write_location (sec, locus); + source_range range = get_range_from_loc (line_table, loc); + if (range.m_start == locus) + /* Compress. */ + range.m_start = UNKNOWN_LOCATION; + write_location (sec, range.m_start); + write_location (sec, range.m_finish); + } + else if (IS_MACRO_LOC (loc)) + { + if (const loc_spans::span *span = spans.macro (loc)) + { + unsigned off = MAX_LOCATION_T - loc; + + off -= span->macro_delta; + + sec.u (LK_MACRO); + sec.u (off); + dump (dumper::LOCATION) + && dump ("Macro location %u output %u", loc, off); + } + else if (const module_state *import = module_for_macro_loc (loc)) + { + unsigned off = import->macro_locs.second - loc - 1; + sec.u (LK_IMPORT_MACRO); + sec.u (import->remap); + sec.u (off); + dump (dumper::LOCATION) + && dump ("Imported macro location %u output %u:%u", + loc, import->remap, off); + } + else + gcc_unreachable (); + } + else if (IS_ORDINARY_LOC (loc)) + { + if (const loc_spans::span *span = spans.ordinary (loc)) + { + unsigned off = loc; + + off += span->ordinary_delta; + sec.u (LK_ORDINARY); + sec.u (off); + + dump (dumper::LOCATION) + && dump ("Ordinary location %u output %u", loc, off); + } + else if (const module_state *import = module_for_ordinary_loc (loc)) + { + unsigned off = loc - import->ordinary_locs.first; + sec.u (LK_IMPORT_ORDINARY); + sec.u (import->remap); + sec.u (off); + dump (dumper::LOCATION) + && dump ("Imported ordinary location %u output %u:%u", + import->remap, import->remap, off); + } + else + gcc_unreachable (); + } + else + gcc_unreachable (); +} + +location_t +module_state::read_location (bytes_in &sec) const +{ + location_t locus = UNKNOWN_LOCATION; + unsigned kind = sec.u (); + switch (kind) + { + default: + { + if (kind < LK_RESERVED + RESERVED_LOCATION_COUNT) + locus = location_t (kind - LK_RESERVED); + else + sec.set_overrun (); + dump (dumper::LOCATION) + && dump ("Reserved location %u", unsigned (locus)); + } + break; + + case LK_ADHOC: + { + dump (dumper::LOCATION) && dump ("Adhoc location"); + locus = read_location (sec); + source_range range; + range.m_start = read_location (sec); + if (range.m_start == UNKNOWN_LOCATION) + range.m_start = locus; + range.m_finish = read_location (sec); + if (locus != loc && range.m_start != loc && range.m_finish != loc) + locus = get_combined_adhoc_loc (line_table, locus, range, NULL); + } + break; + + case LK_MACRO: + { + unsigned off = sec.u (); + + if (macro_locs.first) + { + location_t adjusted = MAX_LOCATION_T - off; + adjusted -= slurp->loc_deltas.second; + if (adjusted < macro_locs.first) + sec.set_overrun (); + else if (adjusted < macro_locs.second) + locus = adjusted; + else + sec.set_overrun (); + } + else + locus = loc; + dump (dumper::LOCATION) + && dump ("Macro %u becoming %u", off, locus); + } + break; + + case LK_ORDINARY: + { + unsigned off = sec.u (); + if (ordinary_locs.second) + { + location_t adjusted = off; + + adjusted += slurp->loc_deltas.first; + if (adjusted >= ordinary_locs.second) + sec.set_overrun (); + else if (adjusted >= ordinary_locs.first) + locus = adjusted; + else if (adjusted < spans.main_start ()) + locus = off; + } + else + locus = loc; + + dump (dumper::LOCATION) + && dump ("Ordinary location %u becoming %u", off, locus); + } + break; + + case LK_IMPORT_MACRO: + case LK_IMPORT_ORDINARY: + { + unsigned mod = sec.u (); + unsigned off = sec.u (); + const module_state *import = NULL; + + if (!mod && !slurp->remap) + /* This is an early read of a partition location during the + read of our ordinary location map. */ + import = this; + else + { + mod = slurp->remap_module (mod); + if (!mod) + sec.set_overrun (); + else + import = (*modules)[mod]; + } + + if (import) + { + if (kind == LK_IMPORT_MACRO) + { + if (!import->macro_locs.first) + locus = import->loc; + else if (off < import->macro_locs.second - macro_locs.first) + locus = import->macro_locs.second - off - 1; + else + sec.set_overrun (); + } + else + { + if (!import->ordinary_locs.second) + locus = import->loc; + else if (off < (import->ordinary_locs.second + - import->ordinary_locs.first)) + locus = import->ordinary_locs.first + off; + else + sec.set_overrun (); + } + } + } + break; + } + + return locus; +} + +/* Prepare the span adjustments. */ + +// FIXME:QOI I do not prune the unreachable locations. Modules with +// textually-large GMFs could well cause us to run out of locations. +// Regular single-file modules could also be affected. We should +// determine which locations we need to represent, so that we do not +// grab more locations than necessary. An example is in +// write_macro_maps where we work around macro expansions that are not +// covering any locations -- the macro expands to nothing. Perhaps we +// should decompose locations so that we can have a more graceful +// degradation upon running out? + +location_map_info +module_state::write_prepare_maps (module_state_config *) +{ + dump () && dump ("Preparing locations"); + dump.indent (); + + dump () && dump ("Reserved locations [%u,%u) macro [%u,%u)", + spans[loc_spans::SPAN_RESERVED].ordinary.first, + spans[loc_spans::SPAN_RESERVED].ordinary.second, + spans[loc_spans::SPAN_RESERVED].macro.first, + spans[loc_spans::SPAN_RESERVED].macro.second); + + location_map_info info; + + info.num_maps.first = info.num_maps.second = 0; + + /* Figure the alignment of ordinary location spans. */ + unsigned max_range = 0; + for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) + { + loc_spans::span &span = spans[ix]; + line_map_ordinary const *omap + = linemap_check_ordinary (linemap_lookup (line_table, + span.ordinary.first)); + + /* We should exactly match up. */ + gcc_checking_assert (MAP_START_LOCATION (omap) == span.ordinary.first); + + line_map_ordinary const *fmap = omap; + for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) + { + /* We should never find a module linemap in an interval. */ + gcc_checking_assert (!MAP_MODULE_P (omap)); + + if (max_range < omap->m_range_bits) + max_range = omap->m_range_bits; + } + + unsigned count = omap - fmap; + info.num_maps.first += count; + + if (span.macro.first != span.macro.second) + { + count = linemap_lookup_macro_index (line_table, span.macro.first) + 1; + count -= linemap_lookup_macro_index (line_table, + span.macro.second - 1); + dump (dumper::LOCATION) && dump ("Span:%u %u macro maps", ix, count); + info.num_maps.second += count; + } + } + + /* Adjust the maps. Ordinary ones ascend, and we must maintain + alignment. Macro ones descend, but are unaligned. */ + location_t ord_off = spans[loc_spans::SPAN_FIRST].ordinary.first; + location_t mac_off = spans[loc_spans::SPAN_FIRST].macro.second; + location_t range_mask = (1u << max_range) - 1; + + dump () && dump ("Ordinary maps range bits:%u, preserve:%x, zero:%u", + max_range, ord_off & range_mask, ord_off & ~range_mask); + + for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) + { + loc_spans::span &span = spans[ix]; + + span.macro_delta = mac_off - span.macro.second; + mac_off -= span.macro.second - span.macro.first; + dump () && dump ("Macro span:%u [%u,%u):%u->%d(%u)", ix, + span.macro.first, span.macro.second, + span.macro.second - span.macro.first, + span.macro_delta, span.macro.first + span.macro_delta); + + line_map_ordinary const *omap + = linemap_check_ordinary (linemap_lookup (line_table, + span.ordinary.first)); + location_t base = MAP_START_LOCATION (omap); + + /* Preserve the low MAX_RANGE bits of base by incrementing ORD_OFF. */ + unsigned low_bits = base & range_mask; + if ((ord_off & range_mask) > low_bits) + low_bits += range_mask + 1; + ord_off = (ord_off & ~range_mask) + low_bits; + span.ordinary_delta = ord_off - base; + + for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) + { + location_t start_loc = MAP_START_LOCATION (omap); + unsigned to = start_loc + span.ordinary_delta; + location_t end_loc = MAP_START_LOCATION (omap + 1); + + dump () && dump ("Ordinary span:%u [%u,%u):%u->%d(%u)", ix, start_loc, + end_loc, end_loc - start_loc, + span.ordinary_delta, to); + + /* There should be no change in the low order bits. */ + gcc_checking_assert (((start_loc ^ to) & range_mask) == 0); + } + /* The ending serialized value. */ + ord_off = span.ordinary.second + span.ordinary_delta; + } + + dump () && dump ("Ordinary hwm:%u macro lwm:%u", ord_off, mac_off); + + dump.outdent (); + + info.max_range = max_range; + + return info; +} + +bool +module_state::read_prepare_maps (const module_state_config *cfg) +{ + location_t ordinary = line_table->highest_location + 1; + ordinary = ((ordinary + (1u << cfg->ordinary_loc_align)) + & ~((1u << cfg->ordinary_loc_align) - 1)); + ordinary += cfg->ordinary_locs; + + location_t macro = LINEMAPS_MACRO_LOWEST_LOCATION (line_table); + macro -= cfg->macro_locs; + + if (ordinary < LINE_MAP_MAX_LOCATION_WITH_COLS + && macro >= LINE_MAP_MAX_LOCATION) + /* OK, we have enough locations. */ + return true; + + ordinary_locs.first = ordinary_locs.second = 0; + macro_locs.first = macro_locs.second = 0; + + static bool informed = false; + if (!informed) + { + /* Just give the notice once. */ + informed = true; + inform (loc, "unable to represent further imported source locations"); + } + + return false; +} + +/* Write the location maps. This also determines the shifts for the + location spans. */ + +void +module_state::write_ordinary_maps (elf_out *to, location_map_info &info, + module_state_config *cfg, bool has_partitions, + unsigned *crc_p) +{ + dump () && dump ("Writing ordinary location maps"); + dump.indent (); + + vec<const char *> filenames; + filenames.create (20); + + /* Determine the unique filenames. */ + // FIXME:QOI We should find the set of filenames when working out + // which locations we actually need. See write_prepare_maps. + for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) + { + loc_spans::span &span = spans[ix]; + line_map_ordinary const *omap + = linemap_check_ordinary (linemap_lookup (line_table, + span.ordinary.first)); + + /* We should exactly match up. */ + gcc_checking_assert (MAP_START_LOCATION (omap) == span.ordinary.first); + + for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) + { + const char *fname = ORDINARY_MAP_FILE_NAME (omap); + + /* We should never find a module linemap in an interval. */ + gcc_checking_assert (!MAP_MODULE_P (omap)); + + /* We expect very few filenames, so just an array. */ + for (unsigned jx = filenames.length (); jx--;) + { + const char *name = filenames[jx]; + if (0 == strcmp (name, fname)) + { + /* Reset the linemap's name, because for things like + preprocessed input we could have multple + instances of the same name, and we'd rather not + percolate that. */ + const_cast<line_map_ordinary *> (omap)->to_file = name; + fname = NULL; + break; + } + } + if (fname) + filenames.safe_push (fname); + } + } + + bytes_out sec (to); + sec.begin (); + + /* Write the filenames. */ + unsigned len = filenames.length (); + sec.u (len); + dump () && dump ("%u source file names", len); + for (unsigned ix = 0; ix != len; ix++) + { + const char *fname = filenames[ix]; + dump (dumper::LOCATION) && dump ("Source file[%u]=%s", ix, fname); + sec.str (fname); + } + + location_t offset = spans[loc_spans::SPAN_FIRST].ordinary.first; + location_t range_mask = (1u << info.max_range) - 1; + + dump () && dump ("Ordinary maps:%u, range bits:%u, preserve:%x, zero:%u", + info.num_maps.first, info.max_range, offset & range_mask, + offset & ~range_mask); + sec.u (info.num_maps.first); /* Num maps. */ + sec.u (info.max_range); /* Maximum range bits */ + sec.u (offset & range_mask); /* Bits to preserve. */ + sec.u (offset & ~range_mask); + + for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) + { + loc_spans::span &span = spans[ix]; + line_map_ordinary const *omap + = linemap_check_ordinary (linemap_lookup (line_table, + span.ordinary.first)); + for (; MAP_START_LOCATION (omap) < span.ordinary.second; omap++) + { + location_t start_loc = MAP_START_LOCATION (omap); + unsigned to = start_loc + span.ordinary_delta; + + dump (dumper::LOCATION) + && dump ("Span:%u ordinary [%u,%u)->%u", ix, start_loc, + MAP_START_LOCATION (omap + 1), to); + + /* There should be no change in the low order bits. */ + gcc_checking_assert (((start_loc ^ to) & range_mask) == 0); + sec.u (to); + + /* Making accessors just for here, seems excessive. */ + sec.u (omap->reason); + sec.u (omap->sysp); + sec.u (omap->m_range_bits); + sec.u (omap->m_column_and_range_bits - omap->m_range_bits); + + const char *fname = ORDINARY_MAP_FILE_NAME (omap); + for (unsigned ix = 0; ix != filenames.length (); ix++) + if (filenames[ix] == fname) + { + sec.u (ix); + break; + } + sec.u (ORDINARY_MAP_STARTING_LINE_NUMBER (omap)); + + /* Write the included from location, which means reading it + while reading in the ordinary maps. So we'd better not + be getting ahead of ourselves. */ + location_t from = linemap_included_from (omap); + gcc_checking_assert (from < MAP_START_LOCATION (omap)); + if (from != UNKNOWN_LOCATION && has_partitions) + { + /* A partition's span will have a from pointing at a + MODULE_INC. Find that map's from. */ + line_map_ordinary const *fmap + = linemap_check_ordinary (linemap_lookup (line_table, from)); + if (MAP_MODULE_P (fmap)) + from = linemap_included_from (fmap); + } + write_location (sec, from); + } + /* The ending serialized value. */ + offset = MAP_START_LOCATION (omap) + span.ordinary_delta; + } + dump () && dump ("Ordinary location hwm:%u", offset); + sec.u (offset); + + // Record number of locations and alignment. + cfg->ordinary_loc_align = info.max_range; + cfg->ordinary_locs = offset; + + filenames.release (); + + sec.end (to, to->name (MOD_SNAME_PFX ".olm"), crc_p); + dump.outdent (); +} + +void +module_state::write_macro_maps (elf_out *to, location_map_info &info, + module_state_config *cfg, unsigned *crc_p) +{ + dump () && dump ("Writing macro location maps"); + dump.indent (); + + bytes_out sec (to); + sec.begin (); + + dump () && dump ("Macro maps:%u", info.num_maps.second); + sec.u (info.num_maps.second); + + location_t offset = spans[loc_spans::SPAN_FIRST].macro.second; + sec.u (offset); + + unsigned macro_num = 0; + for (unsigned ix = loc_spans::SPAN_FIRST; ix != spans.length (); ix++) + { + loc_spans::span &span = spans[ix]; + if (span.macro.first == span.macro.second) + continue; + + for (unsigned first + = linemap_lookup_macro_index (line_table, span.macro.second - 1); + first < LINEMAPS_MACRO_USED (line_table); + first++) + { + line_map_macro const *mmap + = LINEMAPS_MACRO_MAP_AT (line_table, first); + location_t start_loc = MAP_START_LOCATION (mmap); + if (start_loc < span.macro.first) + break; + if (macro_num == info.num_maps.second) + { + /* We're ending on an empty macro expansion. The + preprocessor doesn't prune such things. */ + // FIXME:QOI This is an example of the non-pruning of + // locations. See write_prepare_maps. + gcc_checking_assert (!mmap->n_tokens); + continue; + } + + sec.u (offset); + sec.u (mmap->n_tokens); + sec.cpp_node (mmap->macro); + write_location (sec, mmap->expansion); + const location_t *locs = mmap->macro_locations; + /* There are lots of identical runs. */ + location_t prev = UNKNOWN_LOCATION; + unsigned count = 0; + unsigned runs = 0; + for (unsigned jx = mmap->n_tokens * 2; jx--;) + { + location_t tok_loc = locs[jx]; + if (tok_loc == prev) + { + count++; + continue; + } + runs++; + sec.u (count); + count = 1; + prev = tok_loc; + write_location (sec, tok_loc); + } + sec.u (count); + dump (dumper::LOCATION) + && dump ("Span:%u macro:%u %I %u/%u*2 locations [%u,%u)->%u", + ix, macro_num, identifier (mmap->macro), + runs, mmap->n_tokens, + start_loc, start_loc + mmap->n_tokens, + start_loc + span.macro_delta); + macro_num++; + offset -= mmap->n_tokens; + gcc_checking_assert (offset == start_loc + span.macro_delta); + } + } + dump () && dump ("Macro location lwm:%u", offset); + sec.u (offset); + gcc_assert (macro_num == info.num_maps.second); + + cfg->macro_locs = MAX_LOCATION_T + 1 - offset; + + sec.end (to, to->name (MOD_SNAME_PFX ".mlm"), crc_p); + dump.outdent (); +} + +bool +module_state::read_ordinary_maps () +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".olm")) + return false; + dump () && dump ("Reading ordinary location maps"); + dump.indent (); + + /* Read the filename table. */ + unsigned len = sec.u (); + dump () && dump ("%u source file names", len); + vec<const char *> filenames; + filenames.create (len); + for (unsigned ix = 0; ix != len; ix++) + { + size_t l; + const char *buf = sec.str (&l); + char *fname = XNEWVEC (char, l + 1); + memcpy (fname, buf, l + 1); + dump (dumper::LOCATION) && dump ("Source file[%u]=%s", ix, fname); + /* We leak these names into the line-map table. But it + doesn't own them. */ + filenames.quick_push (fname); + } + + unsigned num_ordinary = sec.u (); + unsigned max_range = sec.u (); + unsigned low_bits = sec.u (); + location_t zero = sec.u (); + location_t range_mask = (1u << max_range) - 1; + + dump () && dump ("Ordinary maps:%u, range bits:%u, preserve:%x, zero:%u", + num_ordinary, max_range, low_bits, zero); + + location_t offset = line_table->highest_location + 1; + /* Ensure offset doesn't go backwards at the start. */ + if ((offset & range_mask) > low_bits) + offset += range_mask + 1; + offset = (offset & ~range_mask); + + bool propagated = spans.maybe_propagate (this, offset + low_bits); + + line_map_ordinary *maps = static_cast<line_map_ordinary *> + (line_map_new_raw (line_table, false, num_ordinary)); + + location_t lwm = offset; + slurp->loc_deltas.first = offset - zero; + ordinary_locs.first = zero + low_bits + slurp->loc_deltas.first; + dump () && dump ("Ordinary loc delta %d", slurp->loc_deltas.first); + + for (unsigned ix = 0; ix != num_ordinary && !sec.get_overrun (); ix++) + { + line_map_ordinary *map = &maps[ix]; + unsigned hwm = sec.u (); + + /* Record the current HWM so that the below read_location is + ok. */ + ordinary_locs.second = hwm + slurp->loc_deltas.first; + map->start_location = hwm + (offset - zero); + if (map->start_location < lwm) + sec.set_overrun (); + lwm = map->start_location; + dump (dumper::LOCATION) && dump ("Map:%u %u->%u", ix, hwm, lwm); + map->reason = lc_reason (sec.u ()); + map->sysp = sec.u (); + map->m_range_bits = sec.u (); + map->m_column_and_range_bits = map->m_range_bits + sec.u (); + + unsigned fnum = sec.u (); + map->to_file = (fnum < filenames.length () ? filenames[fnum] : ""); + map->to_line = sec.u (); + + /* Root the outermost map at our location. */ + location_t from = read_location (sec); + map->included_from = from != UNKNOWN_LOCATION ? from : loc; + } + + location_t hwm = sec.u (); + ordinary_locs.second = hwm + slurp->loc_deltas.first; + + /* highest_location is the one handed out, not the next one to + hand out. */ + line_table->highest_location = ordinary_locs.second - 1; + + if (line_table->highest_location >= LINE_MAP_MAX_LOCATION_WITH_COLS) + /* We shouldn't run out of locations, as we checked before + starting. */ + sec.set_overrun (); + dump () && dump ("Ordinary location hwm:%u", ordinary_locs.second); + + if (propagated) + spans.close (); + + filenames.release (); + + dump.outdent (); + if (!sec.end (from ())) + return false; + + return true; +} + +bool +module_state::read_macro_maps () +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".mlm")) + return false; + dump () && dump ("Reading macro location maps"); + dump.indent (); + + unsigned num_macros = sec.u (); + location_t zero = sec.u (); + dump () && dump ("Macro maps:%u zero:%u", num_macros, zero); + + bool propagated = spans.maybe_propagate (this); + + location_t offset = LINEMAPS_MACRO_LOWEST_LOCATION (line_table); + slurp->loc_deltas.second = zero - offset; + macro_locs.second = zero - slurp->loc_deltas.second; + dump () && dump ("Macro loc delta %d", slurp->loc_deltas.second); + + for (unsigned ix = 0; ix != num_macros && !sec.get_overrun (); ix++) + { + unsigned lwm = sec.u (); + /* Record the current LWM so that the below read_location is + ok. */ + macro_locs.first = lwm - slurp->loc_deltas.second; + + unsigned n_tokens = sec.u (); + cpp_hashnode *node = sec.cpp_node (); + location_t exp_loc = read_location (sec); + + const line_map_macro *macro + = linemap_enter_macro (line_table, node, exp_loc, n_tokens); + if (!macro) + /* We shouldn't run out of locations, as we checked that we + had enough before starting. */ + break; + + location_t *locs = macro->macro_locations; + location_t tok_loc = UNKNOWN_LOCATION; + unsigned count = sec.u (); + unsigned runs = 0; + for (unsigned jx = macro->n_tokens * 2; jx-- && !sec.get_overrun ();) + { + while (!count-- && !sec.get_overrun ()) + { + runs++; + tok_loc = read_location (sec); + count = sec.u (); + } + locs[jx] = tok_loc; + } + if (count) + sec.set_overrun (); + dump (dumper::LOCATION) + && dump ("Macro:%u %I %u/%u*2 locations [%u,%u)", + ix, identifier (node), runs, n_tokens, + MAP_START_LOCATION (macro), + MAP_START_LOCATION (macro) + n_tokens); + } + location_t lwm = sec.u (); + macro_locs.first = lwm - slurp->loc_deltas.second; + + dump () && dump ("Macro location lwm:%u", macro_locs.first); + + if (propagated) + spans.close (); + + dump.outdent (); + if (!sec.end (from ())) + return false; + + return true; +} + +/* Serialize the definition of MACRO. */ + +void +module_state::write_define (bytes_out &sec, const cpp_macro *macro, bool located) +{ + sec.u (macro->count); + + sec.b (macro->fun_like); + sec.b (macro->variadic); + sec.b (macro->syshdr); + sec.bflush (); + + if (located) + write_location (sec, macro->line); + if (macro->fun_like) + { + sec.u (macro->paramc); + const cpp_hashnode *const *parms = macro->parm.params; + for (unsigned ix = 0; ix != macro->paramc; ix++) + sec.cpp_node (parms[ix]); + } + + unsigned len = 0; + for (unsigned ix = 0; ix != macro->count; ix++) + { + const cpp_token *token = ¯o->exp.tokens[ix]; + if (located) + write_location (sec, token->src_loc); + sec.u (token->type); + sec.u (token->flags); + switch (cpp_token_val_index (token)) + { + default: + gcc_unreachable (); + + case CPP_TOKEN_FLD_ARG_NO: + /* An argument reference. */ + sec.u (token->val.macro_arg.arg_no); + sec.cpp_node (token->val.macro_arg.spelling); + break; + + case CPP_TOKEN_FLD_NODE: + /* An identifier. */ + sec.cpp_node (token->val.node.node); + if (token->val.node.spelling == token->val.node.node) + /* The spelling will usually be the same. so optimize + that. */ + sec.str (NULL, 0); + else + sec.cpp_node (token->val.node.spelling); + break; + + case CPP_TOKEN_FLD_NONE: + break; + + case CPP_TOKEN_FLD_STR: + /* A string, number or comment. Not always NUL terminated, + we stream out in a single contatenation with embedded + NULs as that's a safe default. */ + len += token->val.str.len + 1; + sec.u (token->val.str.len); + break; + + case CPP_TOKEN_FLD_SOURCE: + case CPP_TOKEN_FLD_TOKEN_NO: + case CPP_TOKEN_FLD_PRAGMA: + /* These do not occur inside a macro itself. */ + gcc_unreachable (); + } + } + + if (len) + { + char *ptr = reinterpret_cast<char *> (sec.buf (len)); + len = 0; + for (unsigned ix = 0; ix != macro->count; ix++) + { + const cpp_token *token = ¯o->exp.tokens[ix]; + if (cpp_token_val_index (token) == CPP_TOKEN_FLD_STR) + { + memcpy (ptr + len, token->val.str.text, + token->val.str.len); + len += token->val.str.len; + ptr[len++] = 0; + } + } + } +} + +/* Read a macro definition. */ + +cpp_macro * +module_state::read_define (bytes_in &sec, cpp_reader *reader, bool located) const +{ + unsigned count = sec.u (); + /* We rely on knowing cpp_reader's hash table is ident_hash, and + it's subobject allocator is stringpool_ggc_alloc and that is just + a wrapper for ggc_alloc_atomic. */ + cpp_macro *macro + = (cpp_macro *)ggc_alloc_atomic (sizeof (cpp_macro) + + sizeof (cpp_token) * (count - !!count)); + memset (macro, 0, sizeof (cpp_macro) + sizeof (cpp_token) * (count - !!count)); + + macro->count = count; + macro->kind = cmk_macro; + macro->imported_p = true; + + macro->fun_like = sec.b (); + macro->variadic = sec.b (); + macro->syshdr = sec.b (); + sec.bflush (); + + macro->line = located ? read_location (sec) : loc; + + if (macro->fun_like) + { + unsigned paramc = sec.u (); + cpp_hashnode **params + = (cpp_hashnode **)ggc_alloc_atomic (sizeof (cpp_hashnode *) * paramc); + macro->paramc = paramc; + macro->parm.params = params; + for (unsigned ix = 0; ix != paramc; ix++) + params[ix] = sec.cpp_node (); + } + + unsigned len = 0; + for (unsigned ix = 0; ix != count && !sec.get_overrun (); ix++) + { + cpp_token *token = ¯o->exp.tokens[ix]; + token->src_loc = located ? read_location (sec) : loc; + token->type = cpp_ttype (sec.u ()); + token->flags = sec.u (); + switch (cpp_token_val_index (token)) + { + default: + sec.set_overrun (); + break; + + case CPP_TOKEN_FLD_ARG_NO: + /* An argument reference. */ + { + unsigned arg_no = sec.u (); + if (arg_no - 1 >= macro->paramc) + sec.set_overrun (); + token->val.macro_arg.arg_no = arg_no; + token->val.macro_arg.spelling = sec.cpp_node (); + } + break; + + case CPP_TOKEN_FLD_NODE: + /* An identifier. */ + token->val.node.node = sec.cpp_node (); + token->val.node.spelling = sec.cpp_node (); + if (!token->val.node.spelling) + token->val.node.spelling = token->val.node.node; + break; + + case CPP_TOKEN_FLD_NONE: + break; + + case CPP_TOKEN_FLD_STR: + /* A string, number or comment. */ + token->val.str.len = sec.u (); + len += token->val.str.len + 1; + break; + } + } + + if (len) + if (const char *ptr = reinterpret_cast<const char *> (sec.buf (len))) + { + /* There should be a final NUL. */ + if (ptr[len-1]) + sec.set_overrun (); + /* cpp_alloc_token_string will add a final NUL. */ + const unsigned char *buf + = cpp_alloc_token_string (reader, (const unsigned char *)ptr, len - 1); + len = 0; + for (unsigned ix = 0; ix != count && !sec.get_overrun (); ix++) + { + cpp_token *token = ¯o->exp.tokens[ix]; + if (cpp_token_val_index (token) == CPP_TOKEN_FLD_STR) + { + token->val.str.text = buf + len; + len += token->val.str.len; + if (buf[len++]) + sec.set_overrun (); + } + } + } + + if (sec.get_overrun ()) + return NULL; + return macro; +} + +/* Exported macro data. */ +struct macro_export { + cpp_macro *def; + location_t undef_loc; + + macro_export () + :def (NULL), undef_loc (UNKNOWN_LOCATION) + { + } +}; + +/* Imported macro data. */ +class macro_import { +public: + struct slot { +#if defined (WORDS_BIGENDIAN) && SIZEOF_VOID_P == 8 + int offset; +#endif + /* We need to ensure we don't use the LSB for representation, as + that's the union discriminator below. */ + unsigned bits; + +#if !(defined (WORDS_BIGENDIAN) && SIZEOF_VOID_P == 8) + int offset; +#endif + + public: + enum Layout { + L_DEF = 1, + L_UNDEF = 2, + L_BOTH = 3, + L_MODULE_SHIFT = 2 + }; + + public: + /* Not a regular ctor, because we put it in a union, and that's + not allowed in C++ 98. */ + static slot ctor (unsigned module, unsigned defness) + { + gcc_checking_assert (defness); + slot s; + s.bits = defness | (module << L_MODULE_SHIFT); + s.offset = -1; + return s; + } + + public: + unsigned get_defness () const + { + return bits & L_BOTH; + } + unsigned get_module () const + { + return bits >> L_MODULE_SHIFT; + } + void become_undef () + { + bits &= ~unsigned (L_DEF); + bits |= unsigned (L_UNDEF); + } + }; + +private: + typedef vec<slot, va_heap, vl_embed> ary_t; + union either { + /* Discriminated by bits 0|1 != 0. The expected case is that + there will be exactly one slot per macro, hence the effort of + packing that. */ + ary_t *ary; + slot single; + } u; + +public: + macro_import () + { + u.ary = NULL; + } + +private: + bool single_p () const + { + return u.single.bits & slot::L_BOTH; + } + bool occupied_p () const + { + return u.ary != NULL; + } + +public: + unsigned length () const + { + gcc_checking_assert (occupied_p ()); + return single_p () ? 1 : u.ary->length (); + } + slot &operator[] (unsigned ix) + { + gcc_checking_assert (occupied_p ()); + if (single_p ()) + { + gcc_checking_assert (!ix); + return u.single; + } + else + return (*u.ary)[ix]; + } + +public: + slot &exported (); + slot &append (unsigned module, unsigned defness); +}; + +/* O is a new import to append to the list for. If we're an empty + set, initialize us. */ + +macro_import::slot & +macro_import::append (unsigned module, unsigned defness) +{ + if (!occupied_p ()) + { + u.single = slot::ctor (module, defness); + return u.single; + } + else + { + bool single = single_p (); + ary_t *m = single ? NULL : u.ary; + vec_safe_reserve (m, 1 + single); + if (single) + m->quick_push (u.single); + u.ary = m; + return *u.ary->quick_push (slot::ctor (module, defness)); + } +} + +/* We're going to export something. Make sure the first import slot + is us. */ + +macro_import::slot & +macro_import::exported () +{ + if (occupied_p () && !(*this)[0].get_module ()) + { + slot &res = (*this)[0]; + res.bits |= slot::L_DEF; + return res; + } + + slot *a = &append (0, slot::L_DEF); + if (!single_p ()) + { + slot &f = (*this)[0]; + std::swap (f, *a); + a = &f; + } + return *a; +} + +/* The import (&exported) macros. cpp_hasnode's deferred field + indexes this array (offset by 1, so zero means 'not present'. */ + +static vec<macro_import, va_heap, vl_embed> *macro_imports; + +/* The exported macros. A macro_import slot's zeroth element's offset + indexes this array. If the zeroth slot is not for module zero, + there is no export. */ + +static vec<macro_export, va_heap, vl_embed> *macro_exports; + +/* The reachable set of header imports from this TU. */ + +static GTY(()) bitmap headers; + +/* Get the (possibly empty) macro imports for NODE. */ + +static macro_import & +get_macro_imports (cpp_hashnode *node) +{ + if (node->deferred) + return (*macro_imports)[node->deferred - 1]; + + vec_safe_reserve (macro_imports, 1); + node->deferred = macro_imports->length () + 1; + return *vec_safe_push (macro_imports, macro_import ()); +} + +/* Get the macro export for export EXP of NODE. */ + +static macro_export & +get_macro_export (macro_import::slot &slot) +{ + if (slot.offset >= 0) + return (*macro_exports)[slot.offset]; + + vec_safe_reserve (macro_exports, 1); + slot.offset = macro_exports->length (); + return *macro_exports->quick_push (macro_export ()); +} + +/* If NODE is an exportable macro, add it to the export set. */ + +static int +maybe_add_macro (cpp_reader *, cpp_hashnode *node, void *data_) +{ + bool exporting = false; + + if (cpp_user_macro_p (node)) + if (cpp_macro *macro = node->value.macro) + /* Ignore imported, builtins, command line and forced header macros. */ + if (!macro->imported_p + && !macro->lazy && macro->line >= spans.main_start ()) + { + gcc_checking_assert (macro->kind == cmk_macro); + /* I don't want to deal with this corner case, that I suspect is + a devil's advocate reading of the standard. */ + gcc_checking_assert (!macro->extra_tokens); + + macro_import::slot &slot = get_macro_imports (node).exported (); + macro_export &exp = get_macro_export (slot); + exp.def = macro; + exporting = true; + } + + if (!exporting && node->deferred) + { + macro_import &imports = (*macro_imports)[node->deferred - 1]; + macro_import::slot &slot = imports[0]; + if (!slot.get_module ()) + { + gcc_checking_assert (slot.get_defness ()); + exporting = true; + } + } + + if (exporting) + static_cast<vec<cpp_hashnode *> *> (data_)->safe_push (node); + + return 1; /* Don't stop. */ +} + +/* Order cpp_hashnodes A_ and B_ by their exported macro locations. */ + +static int +macro_loc_cmp (const void *a_, const void *b_) +{ + const cpp_hashnode *node_a = *(const cpp_hashnode *const *)a_; + macro_import &import_a = (*macro_imports)[node_a->deferred - 1]; + const macro_export &export_a = (*macro_exports)[import_a[0].offset]; + location_t loc_a = export_a.def ? export_a.def->line : export_a.undef_loc; + + const cpp_hashnode *node_b = *(const cpp_hashnode *const *)b_; + macro_import &import_b = (*macro_imports)[node_b->deferred - 1]; + const macro_export &export_b = (*macro_exports)[import_b[0].offset]; + location_t loc_b = export_b.def ? export_b.def->line : export_b.undef_loc; + + if (loc_a < loc_b) + return +1; + else if (loc_a > loc_b) + return -1; + else + return 0; +} + +/* Write out the exported defines. This is two sections, one + containing the definitions, the other a table of node names. */ + +unsigned +module_state::write_macros (elf_out *to, cpp_reader *reader, unsigned *crc_p) +{ + dump () && dump ("Writing macros"); + dump.indent (); + + vec<cpp_hashnode *> macros; + macros.create (100); + cpp_forall_identifiers (reader, maybe_add_macro, ¯os); + + dump (dumper::MACRO) && dump ("No more than %u macros", macros.length ()); + + macros.qsort (macro_loc_cmp); + + /* Write the defs */ + bytes_out sec (to); + sec.begin (); + + unsigned count = 0; + for (unsigned ix = macros.length (); ix--;) + { + cpp_hashnode *node = macros[ix]; + macro_import::slot &slot = (*macro_imports)[node->deferred - 1][0]; + gcc_assert (!slot.get_module () && slot.get_defness ()); + + macro_export &mac = (*macro_exports)[slot.offset]; + gcc_assert (!!(slot.get_defness () & macro_import::slot::L_UNDEF) + == (mac.undef_loc != UNKNOWN_LOCATION) + && !!(slot.get_defness () & macro_import::slot::L_DEF) + == (mac.def != NULL)); + + if (IDENTIFIER_KEYWORD_P (identifier (node))) + { + warning_at (mac.def->line, 0, + "not exporting %<#define %E%> as it is a keyword", + identifier (node)); + slot.offset = 0; + continue; + } + + count++; + slot.offset = sec.pos; + dump (dumper::MACRO) + && dump ("Writing macro %s%s%s %I at %u", + slot.get_defness () & macro_import::slot::L_UNDEF + ? "#undef" : "", + slot.get_defness () == macro_import::slot::L_BOTH + ? " & " : "", + slot.get_defness () & macro_import::slot::L_DEF + ? "#define" : "", + identifier (node), slot.offset); + if (mac.undef_loc != UNKNOWN_LOCATION) + write_location (sec, mac.undef_loc); + if (mac.def) + write_define (sec, mac.def); + } + sec.end (to, to->name (MOD_SNAME_PFX ".def"), crc_p); + + if (count) + { + /* Write the table. */ + bytes_out sec (to); + sec.begin (); + sec.u (count); + + for (unsigned ix = macros.length (); ix--;) + { + const cpp_hashnode *node = macros[ix]; + macro_import::slot &slot = (*macro_imports)[node->deferred - 1][0]; + + if (slot.offset) + { + sec.cpp_node (node); + sec.u (slot.get_defness ()); + sec.u (slot.offset); + } + } + sec.end (to, to->name (MOD_SNAME_PFX ".mac"), crc_p); + } + + macros.release (); + dump.outdent (); + return count; +} + +bool +module_state::read_macros () +{ + /* Get the def section. */ + if (!slurp->macro_defs.begin (loc, from (), MOD_SNAME_PFX ".def")) + return false; + + /* Get the tbl section, if there are defs. */ + if (slurp->macro_defs.more_p () + && !slurp->macro_tbl.begin (loc, from (), MOD_SNAME_PFX ".mac")) + return false; + + return true; +} + +/* Install the macro name table. */ + +void +module_state::install_macros () +{ + bytes_in &sec = slurp->macro_tbl; + if (!sec.size) + return; + + dump () && dump ("Reading macro table %M", this); + dump.indent (); + + unsigned count = sec.u (); + dump () && dump ("%u macros", count); + while (count--) + { + cpp_hashnode *node = sec.cpp_node (); + macro_import &imp = get_macro_imports (node); + unsigned flags = sec.u () & macro_import::slot::L_BOTH; + if (!flags) + sec.set_overrun (); + + if (sec.get_overrun ()) + break; + + macro_import::slot &slot = imp.append (mod, flags); + slot.offset = sec.u (); + + dump (dumper::MACRO) + && dump ("Read %s macro %s%s%s %I at %u", + imp.length () > 1 ? "add" : "new", + flags & macro_import::slot::L_UNDEF ? "#undef" : "", + flags == macro_import::slot::L_BOTH ? " & " : "", + flags & macro_import::slot::L_DEF ? "#define" : "", + identifier (node), slot.offset); + + /* We'll leak an imported definition's TOKEN_FLD_STR's data + here. But that only happens when we've had to resolve the + deferred macro before this import -- why are you doing + that? */ + if (cpp_macro *cur = cpp_set_deferred_macro (node)) + if (!cur->imported_p) + { + macro_import::slot &slot = imp.exported (); + macro_export &exp = get_macro_export (slot); + exp.def = cur; + dump (dumper::MACRO) + && dump ("Saving current #define %I", identifier (node)); + } + } + + /* We're now done with the table. */ + elf_in::release (slurp->from, sec); + + dump.outdent (); +} + +/* Import the transitive macros. */ + +void +module_state::import_macros () +{ + bitmap_ior_into (headers, slurp->headers); + + bitmap_iterator bititer; + unsigned bitnum; + EXECUTE_IF_SET_IN_BITMAP (slurp->headers, 0, bitnum, bititer) + (*modules)[bitnum]->install_macros (); +} + +/* NODE is being undefined at LOC. Record it in the export table, if + necessary. */ + +void +module_state::undef_macro (cpp_reader *, location_t loc, cpp_hashnode *node) +{ + if (!node->deferred) + /* The macro is not imported, so our undef is irrelevant. */ + return; + + unsigned n = dump.push (NULL); + + macro_import::slot &slot = (*macro_imports)[node->deferred - 1].exported (); + macro_export &exp = get_macro_export (slot); + + exp.undef_loc = loc; + slot.become_undef (); + exp.def = NULL; + + dump (dumper::MACRO) && dump ("Recording macro #undef %I", identifier (node)); + + dump.pop (n); +} + +/* NODE is a deferred macro node. Determine the definition and return + it, with NULL if undefined. May issue diagnostics. + + This can leak memory, when merging declarations -- the string + contents (TOKEN_FLD_STR) of each definition are allocated in + unreclaimable cpp objstack. Only one will win. However, I do not + expect this to be common -- mostly macros have a single point of + definition. Perhaps we could restore the objstack to its position + after the first imported definition (if that wins)? The macros + themselves are GC'd. */ + +cpp_macro * +module_state::deferred_macro (cpp_reader *reader, location_t loc, + cpp_hashnode *node) +{ + macro_import &imports = (*macro_imports)[node->deferred - 1]; + + unsigned n = dump.push (NULL); + dump (dumper::MACRO) && dump ("Deferred macro %I", identifier (node)); + + bitmap visible (BITMAP_GGC_ALLOC ()); + + if (!((imports[0].get_defness () & macro_import::slot::L_UNDEF) + && !imports[0].get_module ())) + { + /* Calculate the set of visible header imports. */ + bitmap_copy (visible, headers); + for (unsigned ix = imports.length (); ix--;) + { + const macro_import::slot &slot = imports[ix]; + unsigned mod = slot.get_module (); + if ((slot.get_defness () & macro_import::slot::L_UNDEF) + && bitmap_bit_p (visible, mod)) + { + bitmap arg = mod ? (*modules)[mod]->slurp->headers : headers; + bitmap_and_compl_into (visible, arg); + bitmap_set_bit (visible, mod); + } + } + } + bitmap_set_bit (visible, 0); + + /* Now find the macros that are still visible. */ + bool failed = false; + cpp_macro *def = NULL; + vec<macro_export> defs; + defs.create (imports.length ()); + for (unsigned ix = imports.length (); ix--;) + { + const macro_import::slot &slot = imports[ix]; + unsigned mod = slot.get_module (); + if (bitmap_bit_p (visible, mod)) + { + macro_export *pushed = NULL; + if (mod) + { + const module_state *imp = (*modules)[mod]; + bytes_in &sec = imp->slurp->macro_defs; + if (!sec.get_overrun ()) + { + dump (dumper::MACRO) + && dump ("Reading macro %s%s%s %I module %M at %u", + slot.get_defness () & macro_import::slot::L_UNDEF + ? "#undef" : "", + slot.get_defness () == macro_import::slot::L_BOTH + ? " & " : "", + slot.get_defness () & macro_import::slot::L_DEF + ? "#define" : "", + identifier (node), imp, slot.offset); + sec.random_access (slot.offset); + + macro_export exp; + if (slot.get_defness () & macro_import::slot::L_UNDEF) + exp.undef_loc = imp->read_location (sec); + if (slot.get_defness () & macro_import::slot::L_DEF) + exp.def = imp->read_define (sec, reader); + if (sec.get_overrun ()) + error_at (loc, "macro definitions of %qE corrupted", + imp->name); + else + pushed = defs.quick_push (exp); + } + } + else + pushed = defs.quick_push ((*macro_exports)[slot.offset]); + if (pushed && pushed->def) + { + if (!def) + def = pushed->def; + else if (cpp_compare_macros (def, pushed->def)) + failed = true; + } + } + } + + if (failed) + { + /* If LOC is the first loc, this is the end of file check, which + is a warning. */ + if (loc == MAP_START_LOCATION (LINEMAPS_ORDINARY_MAP_AT (line_table, 0))) + warning_at (loc, OPT_Winvalid_imported_macros, + "inconsistent imported macro definition %qE", + identifier (node)); + else + error_at (loc, "inconsistent imported macro definition %qE", + identifier (node)); + for (unsigned ix = defs.length (); ix--;) + { + macro_export &exp = defs[ix]; + if (exp.undef_loc) + inform (exp.undef_loc, "%<#undef %E%>", identifier (node)); + if (exp.def) + inform (exp.def->line, "%<#define %s%>", + cpp_macro_definition (reader, node, exp.def)); + } + def = NULL; + } + + defs.release (); + + dump.pop (n); + + return def; +} + +/* Stream the static aggregates. Sadly some headers (ahem: + iostream) contain static vars, and rely on them to run global + ctors. */ +unsigned +module_state::write_inits (elf_out *to, depset::hash &table, unsigned *crc_ptr) +{ + if (!static_aggregates && !tls_aggregates) + return 0; + + dump () && dump ("Writing initializers"); + dump.indent (); + + static_aggregates = nreverse (static_aggregates); + tls_aggregates = nreverse (tls_aggregates); + + unsigned count = 0; + trees_out sec (to, this, table, ~0u); + sec.begin (); + + tree list = static_aggregates; + for (int passes = 0; passes != 2; passes++) + { + for (tree init = list; init; init = TREE_CHAIN (init), count++) + if (TREE_LANG_FLAG_0 (init)) + { + tree decl = TREE_VALUE (init); + + dump ("Initializer:%u for %N", count, decl); + sec.tree_node (decl); + } + + list = tls_aggregates; + } + + sec.end (to, to->name (MOD_SNAME_PFX ".ini"), crc_ptr); + dump.outdent (); + + return count; +} + +bool +module_state::read_inits (unsigned count) +{ + trees_in sec (this); + if (!sec.begin (loc, from (), from ()->find (MOD_SNAME_PFX ".ini"))) + return false; + dump () && dump ("Reading %u initializers", count); + dump.indent (); + + for (unsigned ix = 0; ix != count; ix++) + { + /* Merely referencing the decl causes its initializer to be read + and added to the correct list. */ + tree decl = sec.tree_node (); + + if (sec.get_overrun ()) + break; + if (decl) + dump ("Initializer:%u for %N", count, decl); + } + dump.outdent (); + if (!sec.end (from ())) + return false; + return true; +} + +void +module_state::write_counts (elf_out *to, unsigned counts[MSC_HWM], + unsigned *crc_ptr) +{ + bytes_out cfg (to); + + cfg.begin (); + + for (unsigned ix = MSC_HWM; ix--;) + cfg.u (counts[ix]); + + if (dump ()) + { + dump ("Cluster sections are [%u,%u)", + counts[MSC_sec_lwm], counts[MSC_sec_hwm]); + dump ("Bindings %u", counts[MSC_bindings]); + dump ("Pendings %u", counts[MSC_pendings]); + dump ("Entities %u", counts[MSC_entities]); + dump ("Namespaces %u", counts[MSC_namespaces]); + dump ("Macros %u", counts[MSC_macros]); + dump ("Initializers %u", counts[MSC_inits]); + } + + cfg.end (to, to->name (MOD_SNAME_PFX ".cnt"), crc_ptr); +} + +bool +module_state::read_counts (unsigned counts[MSC_HWM]) +{ + bytes_in cfg; + + if (!cfg.begin (loc, from (), MOD_SNAME_PFX ".cnt")) + return false; + + for (unsigned ix = MSC_HWM; ix--;) + counts[ix] = cfg.u (); + + if (dump ()) + { + dump ("Declaration sections are [%u,%u)", + counts[MSC_sec_lwm], counts[MSC_sec_hwm]); + dump ("Bindings %u", counts[MSC_bindings]); + dump ("Pendings %u", counts[MSC_pendings]); + dump ("Entities %u", counts[MSC_entities]); + dump ("Namespaces %u", counts[MSC_namespaces]); + dump ("Macros %u", counts[MSC_macros]); + dump ("Initializers %u", counts[MSC_inits]); + } + + return cfg.end (from ()); +} + +/* Tool configuration: MOD_SNAME_PFX .config + + This is data that confirms current state (or fails). */ + +void +module_state::write_config (elf_out *to, module_state_config &config, + unsigned inner_crc) +{ + bytes_out cfg (to); + + cfg.begin (); + + /* Write version and inner crc as u32 values, for easier + debug inspection. */ + dump () && dump ("Writing version=%V, inner_crc=%x", + MODULE_VERSION, inner_crc); + cfg.u32 (unsigned (MODULE_VERSION)); + cfg.u32 (inner_crc); + + cfg.u (to->name (is_header () ? "" : get_flatname ())); + + /* Configuration. */ + dump () && dump ("Writing target='%s', host='%s'", + TARGET_MACHINE, HOST_MACHINE); + unsigned target = to->name (TARGET_MACHINE); + unsigned host = (!strcmp (TARGET_MACHINE, HOST_MACHINE) + ? target : to->name (HOST_MACHINE)); + cfg.u (target); + cfg.u (host); + + cfg.str (config.dialect_str); + cfg.u (extensions); + + /* Global tree information. We write the globals crc separately, + rather than mix it directly into the overall crc, as it is used + to ensure data match between instances of the compiler, not + integrity of the file. */ + dump () && dump ("Writing globals=%u, crc=%x", + fixed_trees->length (), global_crc); + cfg.u (fixed_trees->length ()); + cfg.u32 (global_crc); + + if (is_partition ()) + cfg.u (is_interface ()); + + cfg.u (config.num_imports); + cfg.u (config.num_partitions); + cfg.u (config.num_entities); + + cfg.u (config.ordinary_locs); + cfg.u (config.macro_locs); + cfg.u (config.ordinary_loc_align); + + /* Now generate CRC, we'll have incorporated the inner CRC because + of its serialization above. */ + cfg.end (to, to->name (MOD_SNAME_PFX ".cfg"), &crc); + dump () && dump ("Writing CRC=%x", crc); +} + +void +module_state::note_cmi_name () +{ + if (!cmi_noted_p && filename) + { + cmi_noted_p = true; + inform (loc, "compiled module file is %qs", + maybe_add_cmi_prefix (filename)); + } +} + +bool +module_state::read_config (module_state_config &config) +{ + bytes_in cfg; + + if (!cfg.begin (loc, from (), MOD_SNAME_PFX ".cfg")) + return false; + + /* Check version. */ + unsigned my_ver = MODULE_VERSION; + unsigned their_ver = cfg.u32 (); + dump () && dump (my_ver == their_ver ? "Version %V" + : "Expecting %V found %V", my_ver, their_ver); + if (their_ver != my_ver) + { + /* The compiler versions differ. Close enough? */ + verstr_t my_string, their_string; + + version2string (my_ver, my_string); + version2string (their_ver, their_string); + + /* Reject when either is non-experimental or when experimental + major versions differ. */ + bool reject_p = ((!IS_EXPERIMENTAL (my_ver) + || !IS_EXPERIMENTAL (their_ver) + || MODULE_MAJOR (my_ver) != MODULE_MAJOR (their_ver)) + /* The 'I know what I'm doing' switch. */ + && !flag_module_version_ignore); + bool inform_p = true; + if (reject_p) + { + cfg.set_overrun (); + error_at (loc, "compiled module is %sversion %s", + IS_EXPERIMENTAL (their_ver) ? "experimental " : "", + their_string); + } + else + inform_p = warning_at (loc, 0, "compiled module is %sversion %s", + IS_EXPERIMENTAL (their_ver) ? "experimental " : "", + their_string); + + if (inform_p) + { + inform (loc, "compiler is %sversion %s%s%s", + IS_EXPERIMENTAL (my_ver) ? "experimental " : "", + my_string, + reject_p ? "" : flag_module_version_ignore + ? ", be it on your own head!" : ", close enough?", + reject_p ? "" : " \xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf"); + note_cmi_name (); + } + + if (reject_p) + goto done; + } + + /* We wrote the inner crc merely to merge it, so simply read it + back and forget it. */ + cfg.u32 (); + + /* Check module name. */ + { + const char *their_name = from ()->name (cfg.u ()); + const char *our_name = ""; + + if (!is_header ()) + our_name = get_flatname (); + + /* Header units can be aliased, so name checking is + inappropriate. */ + if (0 != strcmp (their_name, our_name)) + { + error_at (loc, + their_name[0] && our_name[0] ? G_("module %qs found") + : their_name[0] + ? G_("header module expected, module %qs found") + : G_("module %qs expected, header module found"), + their_name[0] ? their_name : our_name); + cfg.set_overrun (); + goto done; + } + } + + /* Check the CRC after the above sanity checks, so that the user is + clued in. */ + { + unsigned e_crc = crc; + crc = cfg.get_crc (); + dump () && dump ("Reading CRC=%x", crc); + if (!is_direct () && crc != e_crc) + { + error_at (loc, "module %qs CRC mismatch", get_flatname ()); + cfg.set_overrun (); + goto done; + } + } + + /* Check target & host. */ + { + const char *their_target = from ()->name (cfg.u ()); + const char *their_host = from ()->name (cfg.u ()); + dump () && dump ("Read target='%s', host='%s'", their_target, their_host); + if (strcmp (their_target, TARGET_MACHINE) + || strcmp (their_host, HOST_MACHINE)) + { + error_at (loc, "target & host is %qs:%qs, expected %qs:%qs", + their_target, TARGET_MACHINE, their_host, HOST_MACHINE); + cfg.set_overrun (); + goto done; + } + } + + /* Check compilation dialect. This must match. */ + { + const char *their_dialect = cfg.str (); + if (strcmp (their_dialect, config.dialect_str)) + { + error_at (loc, "language dialect differs %qs, expected %qs", + their_dialect, config.dialect_str); + cfg.set_overrun (); + goto done; + } + } + + /* Check for extensions. If they set any, we must have them set + too. */ + { + unsigned ext = cfg.u (); + unsigned allowed = (flag_openmp ? SE_OPENMP : 0); + + if (unsigned bad = ext & ~allowed) + { + if (bad & SE_OPENMP) + error_at (loc, "module contains OpenMP, use %<-fopenmp%> to enable"); + cfg.set_overrun (); + goto done; + } + extensions = ext; + } + + /* Check global trees. */ + { + unsigned their_fixed_length = cfg.u (); + unsigned their_fixed_crc = cfg.u32 (); + dump () && dump ("Read globals=%u, crc=%x", + their_fixed_length, their_fixed_crc); + if (!flag_preprocess_only + && (their_fixed_length != fixed_trees->length () + || their_fixed_crc != global_crc)) + { + error_at (loc, "fixed tree mismatch"); + cfg.set_overrun (); + goto done; + } + } + + /* All non-partitions are interfaces. */ + interface_p = !is_partition () || cfg.u (); + + config.num_imports = cfg.u (); + config.num_partitions = cfg.u (); + config.num_entities = cfg.u (); + + config.ordinary_locs = cfg.u (); + config.macro_locs = cfg.u (); + config.ordinary_loc_align = cfg.u (); + + done: + return cfg.end (from ()); +} + +/* Use ELROND format to record the following sections: + qualified-names : binding value(s) + MOD_SNAME_PFX.README : human readable, strings + MOD_SNAME_PFX.ENV : environment strings, strings + MOD_SNAME_PFX.nms : namespace hierarchy + MOD_SNAME_PFX.bnd : binding table + MOD_SNAME_PFX.spc : specialization table + MOD_SNAME_PFX.imp : import table + MOD_SNAME_PFX.ent : entity table + MOD_SNAME_PFX.prt : partitions table + MOD_SNAME_PFX.olm : ordinary line maps + MOD_SNAME_PFX.mlm : macro line maps + MOD_SNAME_PFX.def : macro definitions + MOD_SNAME_PFX.mac : macro index + MOD_SNAME_PFX.ini : inits + MOD_SNAME_PFX.cnt : counts + MOD_SNAME_PFX.cfg : config data +*/ + +void +module_state::write (elf_out *to, cpp_reader *reader) +{ + /* Figure out remapped module numbers, which might elide + partitions. */ + bitmap partitions = NULL; + if (!is_header () && !is_partition ()) + partitions = BITMAP_GGC_ALLOC (); + + unsigned mod_hwm = 1; + for (unsigned ix = 1; ix != modules->length (); ix++) + { + module_state *imp = (*modules)[ix]; + + /* Promote any non-partition direct import from a partition, unless + we're a partition. */ + if (!is_partition () && !imp->is_partition () + && imp->is_partition_direct ()) + imp->directness = MD_PURVIEW_DIRECT; + + /* Write any import that is not a partition, unless we're a + partition. */ + if (!partitions || !imp->is_partition ()) + imp->remap = mod_hwm++; + else + { + dump () && dump ("Partition %M %u", imp, ix); + bitmap_set_bit (partitions, ix); + imp->remap = 0; + /* All interface partitions must be exported. */ + if (imp->is_interface () && !bitmap_bit_p (exports, imp->mod)) + { + error_at (imp->loc, "interface partition is not exported"); + bitmap_set_bit (exports, imp->mod); + } + + /* All the partition entities should have been loaded when + loading the partition. */ + if (CHECKING_P) + for (unsigned jx = 0; jx != imp->entity_num; jx++) + { + binding_slot *slot = &(*entity_ary)[imp->entity_lwm + jx]; + gcc_checking_assert (!slot->is_lazy ()); + } + } + } + + if (partitions && bitmap_empty_p (partitions)) + /* No partitions present. */ + partitions = nullptr; + + /* Find the set of decls we must write out. */ + depset::hash table (DECL_NAMESPACE_BINDINGS (global_namespace)->size () * 8); + /* Add the specializations before the writables, so that we can + detect injected friend specializations. */ + table.add_specializations (true); + table.add_specializations (false); + if (partial_specializations) + { + table.add_partial_entities (partial_specializations); + partial_specializations = NULL; + } + table.add_namespace_entities (global_namespace, partitions); + if (class_members) + { + table.add_class_entities (class_members); + class_members = NULL; + } + + /* Now join everything up. */ + table.find_dependencies (this); + + if (!table.finalize_dependencies ()) + { + to->set_error (); + return; + } + +#if CHECKING_P + /* We're done verifying at-most once reading, reset to verify + at-most once writing. */ + note_defs = note_defs_table_t::create_ggc (1000); +#endif + + /* Determine Strongy Connected Components. */ + vec<depset *> sccs = table.connect (); + + unsigned crc = 0; + module_state_config config; + location_map_info map_info = write_prepare_maps (&config); + unsigned counts[MSC_HWM]; + + config.num_imports = mod_hwm; + config.num_partitions = modules->length () - mod_hwm; + memset (counts, 0, sizeof (counts)); + + /* depset::cluster is the cluster number, + depset::section is unspecified scratch value. + + The following loops make use of the tarjan property that + dependencies will be earlier in the SCCS array. */ + + /* This first loop determines the number of depsets in each SCC, and + also the number of namespaces we're dealing with. During the + loop, the meaning of a couple of depset fields now change: + + depset::cluster -> size_of cluster, if first of cluster & !namespace + depset::section -> section number of cluster (if !namespace). */ + + unsigned n_spaces = 0; + counts[MSC_sec_lwm] = counts[MSC_sec_hwm] = to->get_section_limit (); + for (unsigned size, ix = 0; ix < sccs.length (); ix += size) + { + depset **base = &sccs[ix]; + + if (base[0]->get_entity_kind () == depset::EK_NAMESPACE) + { + n_spaces++; + size = 1; + } + else + { + /* Count the members in this cluster. */ + for (size = 1; ix + size < sccs.length (); size++) + if (base[size]->cluster != base[0]->cluster) + break; + + for (unsigned jx = 0; jx != size; jx++) + { + /* Set the section number. */ + base[jx]->cluster = ~(~0u >> 1); /* A bad value. */ + base[jx]->section = counts[MSC_sec_hwm]; + } + + /* Save the size in the first member's cluster slot. */ + base[0]->cluster = size; + + counts[MSC_sec_hwm]++; + } + } + + /* Write the clusters. Namespace decls are put in the spaces array. + The meaning of depset::cluster changes to provide the + unnamed-decl count of the depset's decl (and remains zero for + non-decls and non-unnamed). */ + unsigned bytes = 0; + vec<depset *> spaces; + spaces.create (n_spaces); + + for (unsigned size, ix = 0; ix < sccs.length (); ix += size) + { + depset **base = &sccs[ix]; + + if (base[0]->get_entity_kind () == depset::EK_NAMESPACE) + { + tree decl = base[0]->get_entity (); + if (decl == global_namespace) + base[0]->cluster = 0; + else if (!base[0]->is_import ()) + { + base[0]->cluster = counts[MSC_entities]++; + spaces.quick_push (base[0]); + counts[MSC_namespaces]++; + if (CHECKING_P) + { + /* Add it to the entity map, such that we can tell it is + part of us. */ + bool existed; + unsigned *slot = &entity_map->get_or_insert + (DECL_UID (decl), &existed); + if (existed) + /* It must have come from a partition. */ + gcc_checking_assert + (import_entity_module (*slot)->is_partition ()); + *slot = ~base[0]->cluster; + } + dump (dumper::CLUSTER) && dump ("Cluster namespace %N", decl); + } + size = 1; + } + else + { + size = base[0]->cluster; + + /* Cluster is now used to number entities. */ + base[0]->cluster = ~(~0u >> 1); /* A bad value. */ + + sort_cluster (&table, base, size); + + /* Record the section for consistency checking during stream + out -- we don't want to start writing decls in different + sections. */ + table.section = base[0]->section; + bytes += write_cluster (to, base, size, table, counts, &crc); + table.section = 0; + } + } + + /* We'd better have written as many sections and found as many + namespaces as we predicted. */ + gcc_assert (counts[MSC_sec_hwm] == to->get_section_limit () + && spaces.length () == counts[MSC_namespaces]); + + /* Write the entitites. None happens if we contain namespaces or + nothing. */ + config.num_entities = counts[MSC_entities]; + if (counts[MSC_entities]) + write_entities (to, sccs, counts[MSC_entities], &crc); + + /* Write the namespaces. */ + if (counts[MSC_namespaces]) + write_namespaces (to, spaces, counts[MSC_namespaces], &crc); + + /* Write the bindings themselves. */ + counts[MSC_bindings] = write_bindings (to, sccs, &crc); + + /* Write the unnamed. */ + if (counts[MSC_pendings]) + write_pendings (to, sccs, table, counts[MSC_pendings], &crc); + + /* Write the import table. */ + if (config.num_imports > 1) + write_imports (to, &crc); + + /* Write elided partition table. */ + if (config.num_partitions) + write_partitions (to, config.num_partitions, &crc); + + /* Write the line maps. */ + write_ordinary_maps (to, map_info, &config, config.num_partitions, &crc); + write_macro_maps (to, map_info, &config, &crc); + + if (is_header ()) + { + counts[MSC_macros] = write_macros (to, reader, &crc); + counts[MSC_inits] = write_inits (to, table, &crc); + } + + unsigned clusters = counts[MSC_sec_hwm] - counts[MSC_sec_lwm]; + dump () && dump ("Wrote %u clusters, average %u bytes/cluster", + clusters, (bytes + clusters / 2) / (clusters + !clusters)); + + write_counts (to, counts, &crc); + + /* And finish up. */ + write_config (to, config, crc); + + spaces.release (); + sccs.release (); + + /* Human-readable info. */ + write_readme (to, reader, config.dialect_str, extensions); + + // FIXME:QOI: Have a command line switch to control more detailed + // information (which might leak data you do not want to leak). + // Perhaps (some of) the write_readme contents should also be + // so-controlled. + if (false) + write_env (to); + + trees_out::instrument (); + dump () && dump ("Wrote %u sections", to->get_section_limit ()); +} + +/* Initial read of a CMI. Checks config, loads up imports and line + maps. */ + +bool +module_state::read_initial (cpp_reader *reader) +{ + module_state_config config; + bool ok = true; + + if (ok && !from ()->begin (loc)) + ok = false; + + if (ok && !read_config (config)) + ok = false; + + bool have_locs = ok && read_prepare_maps (&config); + + /* Ordinary maps before the imports. */ + if (have_locs && !read_ordinary_maps ()) + ok = false; + + /* Allocate the REMAP vector. */ + slurp->alloc_remap (config.num_imports); + + if (ok) + { + /* Read the import table. Decrement current to stop this CMI + from being evicted during the import. */ + slurp->current--; + if (config.num_imports > 1 && !read_imports (reader, line_table)) + ok = false; + slurp->current++; + } + + /* Read the elided partition table, if we're the primary partition. */ + if (ok && config.num_partitions && is_module () + && !read_partitions (config.num_partitions)) + ok = false; + + /* Determine the module's number. */ + gcc_checking_assert (mod == MODULE_UNKNOWN); + gcc_checking_assert (this != (*modules)[0]); + + { + /* Allocate space in the entities array now -- that array must be + monotionically in step with the modules array. */ + entity_lwm = vec_safe_length (entity_ary); + entity_num = config.num_entities; + gcc_checking_assert (modules->length () == 1 + || modules->last ()->entity_lwm <= entity_lwm); + vec_safe_reserve (entity_ary, config.num_entities); + + binding_slot slot; + slot.u.binding = NULL_TREE; + for (unsigned count = config.num_entities; count--;) + entity_ary->quick_push (slot); + } + + /* We'll run out of other resources before we run out of module + indices. */ + mod = modules->length (); + vec_safe_push (modules, this); + + /* We always import and export ourselves. */ + bitmap_set_bit (imports, mod); + bitmap_set_bit (exports, mod); + + if (ok) + (*slurp->remap)[0] = mod << 1; + dump () && dump ("Assigning %M module number %u", this, mod); + + /* We should not have been frozen during the importing done by + read_config. */ + gcc_assert (!from ()->is_frozen ()); + + /* Macro maps after the imports. */ + if (ok && have_locs && !read_macro_maps ()) + ok = false; + + gcc_assert (slurp->current == ~0u); + return ok; +} + +/* Read a preprocessor state. */ + +bool +module_state::read_preprocessor (bool outermost) +{ + gcc_checking_assert (is_header () && slurp + && slurp->remap_module (0) == mod); + + if (loadedness == ML_PREPROCESSOR) + return !(from () && from ()->get_error ()); + + bool ok = true; + + /* Read direct header imports. */ + unsigned len = slurp->remap->length (); + for (unsigned ix = 1; ok && ix != len; ix++) + { + unsigned map = (*slurp->remap)[ix]; + if (map & 1) + { + module_state *import = (*modules)[map >> 1]; + if (import->is_header ()) + { + ok = import->read_preprocessor (false); + bitmap_ior_into (slurp->headers, import->slurp->headers); + } + } + } + + /* Record as a direct header. */ + if (ok) + bitmap_set_bit (slurp->headers, mod); + + if (ok && !read_macros ()) + ok = false; + + loadedness = ML_PREPROCESSOR; + announce ("macros"); + + if (flag_preprocess_only) + /* We're done with the string table. */ + from ()->release (); + + return check_read (outermost, ok); +} + +static unsigned lazy_snum; + +static bool +recursive_lazy (unsigned snum = ~0u) +{ + if (lazy_snum) + { + error_at (input_location, "recursive lazy load"); + return true; + } + + lazy_snum = snum; + return false; +} + +/* Read language state. */ + +bool +module_state::read_language (bool outermost) +{ + gcc_checking_assert (!lazy_snum); + + if (loadedness == ML_LANGUAGE) + return !(slurp && from () && from ()->get_error ()); + + gcc_checking_assert (slurp && slurp->current == ~0u + && slurp->remap_module (0) == mod); + + bool ok = true; + + /* Read direct imports. */ + unsigned len = slurp->remap->length (); + for (unsigned ix = 1; ok && ix != len; ix++) + { + unsigned map = (*slurp->remap)[ix]; + if (map & 1) + { + module_state *import = (*modules)[map >> 1]; + if (!import->read_language (false)) + ok = false; + } + } + + unsigned counts[MSC_HWM]; + + if (ok && !read_counts (counts)) + ok = false; + + function_depth++; /* Prevent unexpected GCs. */ + + if (counts[MSC_entities] != entity_num) + ok = false; + if (ok && counts[MSC_entities] + && !read_entities (counts[MSC_entities], + counts[MSC_sec_lwm], counts[MSC_sec_hwm])) + ok = false; + + /* Read the namespace hierarchy. */ + if (ok && counts[MSC_namespaces] + && !read_namespaces (counts[MSC_namespaces])) + ok = false; + + if (ok && !read_bindings (counts[MSC_bindings], + counts[MSC_sec_lwm], counts[MSC_sec_hwm])) + ok = false; + + /* And unnamed. */ + if (ok && counts[MSC_pendings] && !read_pendings (counts[MSC_pendings])) + ok = false; + + if (ok) + { + slurp->remaining = counts[MSC_sec_hwm] - counts[MSC_sec_lwm]; + available_clusters += counts[MSC_sec_hwm] - counts[MSC_sec_lwm]; + } + + if (!flag_module_lazy + || (is_partition () + && module_interface_p () + && !module_partition_p ())) + { + /* Read the sections in forward order, so that dependencies are read + first. See note about tarjan_connect. */ + ggc_collect (); + + lazy_snum = ~0u; + + unsigned hwm = counts[MSC_sec_hwm]; + for (unsigned ix = counts[MSC_sec_lwm]; ok && ix != hwm; ix++) + { + if (!load_section (ix, NULL)) + { + ok = false; + break; + } + ggc_collect (); + } + + lazy_snum = 0; + + if (ok && CHECKING_P) + for (unsigned ix = 0; ix != entity_num; ix++) + gcc_assert (!(*entity_ary)[ix + entity_lwm].is_lazy ()); + } + + // If the import is a header-unit, we need to register initializers + // of any static objects it contains (looking at you _Ioinit). + // Notice, the ordering of these initializers will be that of a + // dynamic initializer at this point in the current TU. (Other + // instances of these objects in other TUs will be initialized as + // part of that TU's global initializers.) + if (ok && counts[MSC_inits] && !read_inits (counts[MSC_inits])) + ok = false; + + function_depth--; + + announce (flag_module_lazy ? "lazy" : "imported"); + loadedness = ML_LANGUAGE; + + gcc_assert (slurp->current == ~0u); + + /* We're done with the string table. */ + from ()->release (); + + return check_read (outermost, ok); +} + +bool +module_state::maybe_defrost () +{ + bool ok = true; + if (from ()->is_frozen ()) + { + if (lazy_open >= lazy_limit) + freeze_an_elf (); + dump () && dump ("Defrosting '%s'", filename); + ok = from ()->defrost (maybe_add_cmi_prefix (filename)); + lazy_open++; + } + + return ok; +} + +/* Load section SNUM, dealing with laziness. It doesn't matter if we + have multiple concurrent loads, because we do not use TREE_VISITED + when reading back in. */ + +bool +module_state::load_section (unsigned snum, binding_slot *mslot) +{ + if (from ()->get_error ()) + return false; + + if (snum >= slurp->current) + from ()->set_error (elf::E_BAD_LAZY); + else if (maybe_defrost ()) + { + unsigned old_current = slurp->current; + slurp->current = snum; + slurp->lru = 0; /* Do not swap out. */ + slurp->remaining--; + read_cluster (snum); + slurp->lru = ++lazy_lru; + slurp->current = old_current; + } + + if (mslot && mslot->is_lazy ()) + { + /* Oops, the section didn't set this slot. */ + from ()->set_error (elf::E_BAD_DATA); + *mslot = NULL_TREE; + } + + bool ok = !from ()->get_error (); + if (!ok) + { + error_at (loc, "failed to read compiled module cluster %u: %s", + snum, from ()->get_error (filename)); + note_cmi_name (); + } + + maybe_completed_reading (); + + return ok; +} + +void +module_state::maybe_completed_reading () +{ + if (loadedness == ML_LANGUAGE && slurp->current == ~0u && !slurp->remaining) + { + lazy_open--; + /* We no longer need the macros, all tokenizing has been done. */ + slurp->release_macros (); + + from ()->end (); + slurp->close (); + slurped (); + } +} + +/* After a reading operation, make sure things are still ok. If not, + emit an error and clean up. */ + +bool +module_state::check_read (bool outermost, bool ok) +{ + gcc_checking_assert (!outermost || slurp->current == ~0u); + + if (!ok) + from ()->set_error (); + + if (int e = from ()->get_error ()) + { + error_at (loc, "failed to read compiled module: %s", + from ()->get_error (filename)); + note_cmi_name (); + + if (e == EMFILE + || e == ENFILE +#if MAPPED_READING + || e == ENOMEM +#endif + || false) + inform (loc, "consider using %<-fno-module-lazy%>," + " increasing %<-param-lazy-modules=%u%> value," + " or increasing the per-process file descriptor limit", + param_lazy_modules); + else if (e == ENOENT) + inform (loc, "imports must be built before being imported"); + + if (outermost) + fatal_error (loc, "returning to the gate for a mechanical issue"); + + ok = false; + } + + maybe_completed_reading (); + + return ok; +} + +/* Return the IDENTIFIER_NODE naming module IX. This is the name + including dots. */ + +char const * +module_name (unsigned ix, bool header_ok) +{ + if (modules) + { + module_state *imp = (*modules)[ix]; + + if (ix && !imp->name) + imp = imp->parent; + + if (header_ok || !imp->is_header ()) + return imp->get_flatname (); + } + + return NULL; +} + +/* Return the bitmap describing what modules are imported. Remember, + we always import ourselves. */ + +bitmap +get_import_bitmap () +{ + return (*modules)[0]->imports; +} + +/* Return the visible imports and path of instantiation for an + instantiation at TINST. If TINST is nullptr, we're not in an + instantiation, and thus will return the visible imports of the + current TU (and NULL *PATH_MAP_P). We cache the information on + the tinst level itself. */ + +static bitmap +path_of_instantiation (tinst_level *tinst, bitmap *path_map_p) +{ + gcc_checking_assert (modules_p ()); + + if (!tinst) + { + /* Not inside an instantiation, just the regular case. */ + *path_map_p = nullptr; + return get_import_bitmap (); + } + + if (!tinst->path) + { + /* Calculate. */ + bitmap visible = path_of_instantiation (tinst->next, path_map_p); + bitmap path_map = *path_map_p; + + if (!path_map) + { + path_map = BITMAP_GGC_ALLOC (); + bitmap_set_bit (path_map, 0); + } + + tree decl = tinst->tldcl; + if (TREE_CODE (decl) == TREE_LIST) + decl = TREE_PURPOSE (decl); + if (TYPE_P (decl)) + decl = TYPE_NAME (decl); + + if (unsigned mod = get_originating_module (decl)) + if (!bitmap_bit_p (path_map, mod)) + { + /* This is brand new information! */ + bitmap new_path = BITMAP_GGC_ALLOC (); + bitmap_copy (new_path, path_map); + bitmap_set_bit (new_path, mod); + path_map = new_path; + + bitmap imports = (*modules)[mod]->imports; + if (bitmap_intersect_compl_p (imports, visible)) + { + /* IMPORTS contains additional modules to VISIBLE. */ + bitmap new_visible = BITMAP_GGC_ALLOC (); + + bitmap_ior (new_visible, visible, imports); + visible = new_visible; + } + } + + tinst->path = path_map; + tinst->visible = visible; + } + + *path_map_p = tinst->path; + return tinst->visible; +} + +/* Return the bitmap describing what modules are visible along the + path of instantiation. If we're not an instantiation, this will be + the visible imports of the TU. *PATH_MAP_P is filled in with the + modules owning the instantiation path -- we see the module-linkage + entities of those modules. */ + +bitmap +visible_instantiation_path (bitmap *path_map_p) +{ + if (!modules_p ()) + return NULL; + + return path_of_instantiation (current_instantiation (), path_map_p); +} + +/* We've just directly imported IMPORT. Update our import/export + bitmaps. IS_EXPORT is true if we're reexporting the OTHER. */ + +void +module_state::set_import (module_state const *import, bool is_export) +{ + gcc_checking_assert (this != import); + + /* We see IMPORT's exports (which includes IMPORT). If IMPORT is + the primary interface or a partition we'll see its imports. */ + bitmap_ior_into (imports, import->is_module () || import->is_partition () + ? import->imports : import->exports); + + if (is_export) + /* We'll export OTHER's exports. */ + bitmap_ior_into (exports, import->exports); +} + +/* Return the declaring entity of DECL. That is the decl determining + how to decorate DECL with module information. Returns NULL_TREE if + it's the global module. */ + +tree +get_originating_module_decl (tree decl) +{ + /* An enumeration constant. */ + if (TREE_CODE (decl) == CONST_DECL + && DECL_CONTEXT (decl) + && (TREE_CODE (DECL_CONTEXT (decl)) == ENUMERAL_TYPE)) + decl = TYPE_NAME (DECL_CONTEXT (decl)); + else if (TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == USING_DECL) + { + decl = DECL_CONTEXT (decl); + if (TREE_CODE (decl) != FUNCTION_DECL) + decl = TYPE_NAME (decl); + } + + gcc_checking_assert (TREE_CODE (decl) == TEMPLATE_DECL + || TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == CONCEPT_DECL + || TREE_CODE (decl) == NAMESPACE_DECL); + + for (;;) + { + /* Uninstantiated template friends are owned by the befriending + class -- not their context. */ + if (TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) + decl = TYPE_NAME (DECL_CHAIN (decl)); + + int use; + if (tree ti = node_template_info (decl, use)) + { + decl = TI_TEMPLATE (ti); + if (TREE_CODE (decl) != TEMPLATE_DECL) + { + /* A friend template specialization. */ + gcc_checking_assert (OVL_P (decl)); + return global_namespace; + } + } + else + { + tree ctx = CP_DECL_CONTEXT (decl); + if (TREE_CODE (ctx) == NAMESPACE_DECL) + break; + + if (TYPE_P (ctx)) + { + ctx = TYPE_NAME (ctx); + if (!ctx) + { + /* Some kind of internal type. */ + gcc_checking_assert (DECL_ARTIFICIAL (decl)); + return global_namespace; + } + } + decl = ctx; + } + } + + return decl; +} + +int +get_originating_module (tree decl, bool for_mangle) +{ + tree owner = get_originating_module_decl (decl); + + if (!DECL_LANG_SPECIFIC (owner)) + return for_mangle ? -1 : 0; + + if (for_mangle + && (DECL_MODULE_EXPORT_P (owner) || !DECL_MODULE_PURVIEW_P (owner))) + return -1; + + if (!DECL_MODULE_IMPORT_P (owner)) + return 0; + + return get_importing_module (owner); +} + +unsigned +get_importing_module (tree decl, bool flexible) +{ + unsigned index = import_entity_index (decl, flexible); + if (index == ~(~0u >> 1)) + return -1; + module_state *module = import_entity_module (index); + + return module->mod; +} + +/* Is it permissible to redeclare DECL. */ + +bool +module_may_redeclare (tree decl) +{ + module_state *me = (*modules)[0]; + module_state *them = me; + if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl)) + { + /* We can be given the TEMPLATE_RESULT. We want the + TEMPLATE_DECL. */ + int use_tpl = -1; + if (tree ti = node_template_info (decl, use_tpl)) + { + tree tmpl = TI_TEMPLATE (ti); + if (DECL_TEMPLATE_RESULT (tmpl) == decl) + decl = tmpl; + // FIXME: What about partial specializations? We need to + // look at the specialization list in that case. Unless our + // caller's given us the right thing. An alternative would + // be to put both the template and the result into the + // entity hash, but that seems expensive? + } + unsigned index = import_entity_index (decl); + them = import_entity_module (index); + } + + if (them->is_header ()) + { + if (!header_module_p ()) + return !module_purview_p (); + + if (DECL_SOURCE_LOCATION (decl) == BUILTINS_LOCATION) + /* This is a builtin, being declared in header-unit. We + now need to mark it as an export. */ + DECL_MODULE_EXPORT_P (decl) = true; + + /* If it came from a header, it's in the global module. */ + return true; + } + + if (me == them) + return ((DECL_LANG_SPECIFIC (decl) && DECL_MODULE_PURVIEW_P (decl)) + == module_purview_p ()); + + if (!me->name) + me = me->parent; + + /* We can't have found a GMF entity from a named module. */ + gcc_checking_assert (DECL_LANG_SPECIFIC (decl) + && DECL_MODULE_PURVIEW_P (decl)); + + return me && get_primary (them) == get_primary (me); +} + +/* DECL is being created by this TU. Record it came from here. We + record module purview, so we can see if partial or explicit + specialization needs to be written out, even though its purviewness + comes from the most general template. */ + +void +set_instantiating_module (tree decl) +{ + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == CONCEPT_DECL + || TREE_CODE (decl) == TEMPLATE_DECL + || (TREE_CODE (decl) == NAMESPACE_DECL + && DECL_NAMESPACE_ALIAS (decl))); + + if (!modules_p ()) + return; + + if (!DECL_LANG_SPECIFIC (decl) && module_purview_p ()) + retrofit_lang_decl (decl); + if (DECL_LANG_SPECIFIC (decl)) + { + DECL_MODULE_PURVIEW_P (decl) = module_purview_p (); + /* If this was imported, we'll still be in the entity_hash. */ + DECL_MODULE_IMPORT_P (decl) = false; + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + tree res = DECL_TEMPLATE_RESULT (decl); + retrofit_lang_decl (res); + DECL_MODULE_PURVIEW_P (res) = DECL_MODULE_PURVIEW_P (decl); + DECL_MODULE_IMPORT_P (res) = false; + } + } +} + +/* If DECL is a class member, whose class is not defined in this TU + (it was imported), remember this decl. */ + +void +set_defining_module (tree decl) +{ + gcc_checking_assert (!DECL_LANG_SPECIFIC (decl) + || !DECL_MODULE_IMPORT_P (decl)); + + if (module_has_cmi_p ()) + { + tree ctx = DECL_CONTEXT (decl); + if (ctx + && (TREE_CODE (ctx) == RECORD_TYPE || TREE_CODE (ctx) == UNION_TYPE) + && DECL_LANG_SPECIFIC (TYPE_NAME (ctx)) + && DECL_MODULE_IMPORT_P (TYPE_NAME (ctx))) + { + /* This entity's context is from an import. We may need to + record this entity to make sure we emit it in the CMI. + Template specializations are in the template hash tables, + so we don't need to record them here as well. */ + int use_tpl = -1; + tree ti = node_template_info (decl, use_tpl); + if (use_tpl <= 0) + { + if (ti) + { + gcc_checking_assert (!use_tpl); + /* Get to the TEMPLATE_DECL. */ + decl = TI_TEMPLATE (ti); + } + + /* Record it on the class_members list. */ + vec_safe_push (class_members, decl); + } + } + else if (DECL_IMPLICIT_TYPEDEF_P (decl) + && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) + /* This is a partial or explicit specialization. */ + vec_safe_push (partial_specializations, decl); + } +} + +void +set_originating_module (tree decl, bool friend_p ATTRIBUTE_UNUSED) +{ + set_instantiating_module (decl); + + if (TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL) + return; + + gcc_checking_assert (friend_p || decl == get_originating_module_decl (decl)); + + if (!module_exporting_p ()) + return; + + // FIXME: Check ill-formed linkage + DECL_MODULE_EXPORT_P (decl) = true; +} + +/* DECL is attached to ROOT for odr purposes. */ + +void +maybe_attach_decl (tree ctx, tree decl) +{ + if (!modules_p ()) + return; + + // FIXME: For now just deal with lambdas attached to var decls. + // This might be sufficient? + if (TREE_CODE (ctx) != VAR_DECL) + return; + + gcc_checking_assert (DECL_NAMESPACE_SCOPE_P (ctx)); + + if (!attached_table) + attached_table = new attachset::hash (EXPERIMENT (1, 400)); + + if (attached_table->add (DECL_UID (ctx), decl)) + { + retrofit_lang_decl (ctx); + DECL_MODULE_ATTACHMENTS_P (ctx) = true; + } +} + +/* Create the flat name string. It is simplest to have it handy. */ + +void +module_state::set_flatname () +{ + gcc_checking_assert (!flatname); + if (parent) + { + auto_vec<tree,5> ids; + size_t len = 0; + char const *primary = NULL; + size_t pfx_len = 0; + + for (module_state *probe = this; + probe; + probe = probe->parent) + if (is_partition () && !probe->is_partition ()) + { + primary = probe->get_flatname (); + pfx_len = strlen (primary); + break; + } + else + { + ids.safe_push (probe->name); + len += IDENTIFIER_LENGTH (probe->name) + 1; + } + + char *flat = XNEWVEC (char, pfx_len + len + is_partition ()); + flatname = flat; + + if (primary) + { + memcpy (flat, primary, pfx_len); + flat += pfx_len; + *flat++ = ':'; + } + + for (unsigned len = 0; ids.length ();) + { + if (len) + flat[len++] = '.'; + tree elt = ids.pop (); + unsigned l = IDENTIFIER_LENGTH (elt); + memcpy (flat + len, IDENTIFIER_POINTER (elt), l + 1); + len += l; + } + } + else if (is_header ()) + flatname = TREE_STRING_POINTER (name); + else + flatname = IDENTIFIER_POINTER (name); +} + +/* Read the CMI file for a module. */ + +bool +module_state::do_import (cpp_reader *reader, bool outermost) +{ + gcc_assert (global_namespace == current_scope () && loadedness == ML_NONE); + + loc = linemap_module_loc (line_table, loc, get_flatname ()); + + if (lazy_open >= lazy_limit) + freeze_an_elf (); + + int fd = -1; + int e = ENOENT; + if (filename) + { + const char *file = maybe_add_cmi_prefix (filename); + dump () && dump ("CMI is %s", file); + fd = open (file, O_RDONLY | O_CLOEXEC | O_BINARY); + e = errno; + } + + gcc_checking_assert (!slurp); + slurp = new slurping (new elf_in (fd, e)); + + bool ok = true; + if (!from ()->get_error ()) + { + announce ("importing"); + loadedness = ML_CONFIG; + lazy_open++; + ok = read_initial (reader); + slurp->lru = ++lazy_lru; + } + + gcc_assert (slurp->current == ~0u); + + return check_read (outermost, ok); +} + +/* Attempt to increase the file descriptor limit. */ + +static bool +try_increase_lazy (unsigned want) +{ + gcc_checking_assert (lazy_open >= lazy_limit); + + /* If we're increasing, saturate at hard limit. */ + if (want > lazy_hard_limit && lazy_limit < lazy_hard_limit) + want = lazy_hard_limit; + +#if HAVE_SETRLIMIT + if ((!lazy_limit || !param_lazy_modules) + && lazy_hard_limit + && want <= lazy_hard_limit) + { + struct rlimit rlimit; + rlimit.rlim_cur = want + LAZY_HEADROOM; + rlimit.rlim_max = lazy_hard_limit + LAZY_HEADROOM; + if (!setrlimit (RLIMIT_NOFILE, &rlimit)) + lazy_limit = want; + } +#endif + + return lazy_open < lazy_limit; +} + +/* Pick a victim module to freeze its reader. */ + +void +module_state::freeze_an_elf () +{ + if (try_increase_lazy (lazy_open * 2)) + return; + + module_state *victim = NULL; + for (unsigned ix = modules->length (); ix--;) + { + module_state *candidate = (*modules)[ix]; + if (candidate && candidate->slurp && candidate->slurp->lru + && candidate->from ()->is_freezable () + && (!victim || victim->slurp->lru > candidate->slurp->lru)) + victim = candidate; + } + + if (victim) + { + dump () && dump ("Freezing '%s'", victim->filename); + if (victim->slurp->macro_defs.size) + /* Save the macro definitions to a buffer. */ + victim->from ()->preserve (victim->slurp->macro_defs); + if (victim->slurp->macro_tbl.size) + /* Save the macro definitions to a buffer. */ + victim->from ()->preserve (victim->slurp->macro_tbl); + victim->from ()->freeze (); + lazy_open--; + } + else + dump () && dump ("No module available for freezing"); +} + +/* Load the lazy slot *MSLOT, INDEX'th slot of the module. */ + +bool +module_state::lazy_load (unsigned index, binding_slot *mslot) +{ + unsigned n = dump.push (this); + + gcc_checking_assert (function_depth); + + unsigned cookie = mslot->get_lazy (); + unsigned snum = cookie >> 2; + dump () && dump ("Loading entity %M[%u] section:%u", this, index, snum); + + bool ok = load_section (snum, mslot); + + dump.pop (n); + + return ok; +} + +/* Load MOD's binding for NS::ID into *MSLOT. *MSLOT contains the + lazy cookie. OUTER is true if this is the outermost lazy, (used + for diagnostics). */ + +void +lazy_load_binding (unsigned mod, tree ns, tree id, binding_slot *mslot) +{ + int count = errorcount + warningcount; + + timevar_start (TV_MODULE_IMPORT); + + /* Stop GC happening, even in outermost loads (because our caller + could well be building up a lookup set). */ + function_depth++; + + gcc_checking_assert (mod); + module_state *module = (*modules)[mod]; + unsigned n = dump.push (module); + + unsigned snum = mslot->get_lazy (); + dump () && dump ("Lazily binding %P@%N section:%u", ns, id, + module->name, snum); + + bool ok = !recursive_lazy (snum); + if (ok) + { + ok = module->load_section (snum, mslot); + lazy_snum = 0; + } + + dump.pop (n); + + function_depth--; + + timevar_stop (TV_MODULE_IMPORT); + + if (!ok) + fatal_error (input_location, + module->is_header () + ? G_("failed to load binding %<%E%s%E%>") + : G_("failed to load binding %<%E%s%E@%s%>"), + ns, &"::"[ns == global_namespace ? 2 : 0], id, + module->get_flatname ()); + + if (count != errorcount + warningcount) + inform (input_location, + module->is_header () + ? G_("during load of binding %<%E%s%E%>") + : G_("during load of binding %<%E%s%E@%s%>"), + ns, &"::"[ns == global_namespace ? 2 : 0], id, + module->get_flatname ()); +} + +/* Load any pending specializations of TMPL. Called just before + instantiating TMPL. */ + +void +lazy_load_specializations (tree tmpl) +{ + gcc_checking_assert (DECL_MODULE_PENDING_SPECIALIZATIONS_P (tmpl) + && DECL_MODULE_ENTITY_P (tmpl)); + + int count = errorcount + warningcount; + + timevar_start (TV_MODULE_IMPORT); + bool ok = !recursive_lazy (); + if (ok) + { + unsigned ident = import_entity_index (tmpl); + if (pendset *set = pending_table->get (ident, true)) + { + function_depth++; /* Prevent GC */ + unsigned n = dump.push (NULL); + dump () + && dump ("Reading %u pending specializations keyed to %M[%u] %N", + set->num, import_entity_module (ident), + ident - import_entity_module (ident)->entity_lwm, tmpl); + if (!pendset_lazy_load (set, true)) + ok = false; + dump.pop (n); + + function_depth--; + } + lazy_snum = 0; + } + + timevar_stop (TV_MODULE_IMPORT); + + if (!ok) + fatal_error (input_location, "failed to load specializations keyed to %qD", + tmpl); + + if (count != errorcount + warningcount) + inform (input_location, + "during load of specializations keyed to %qD", tmpl); +} + +void +lazy_load_members (tree decl) +{ + gcc_checking_assert (DECL_MODULE_PENDING_MEMBERS_P (decl)); + if (!DECL_MODULE_ENTITY_P (decl)) + { + // FIXME: I can't help feeling that DECL_TEMPLATE_RESULT should + // be inserted into the entity map, or perhaps have the same + // DECL_UID as the template, so I don't have to do this dance + // here and elsewhere. It also simplifies when DECL is a + // partial specialization. (also noted elsewhere as an issue) + tree ti = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)); + tree tmpl = TI_TEMPLATE (ti); + gcc_checking_assert (DECL_TEMPLATE_RESULT (tmpl) == decl); + decl = tmpl; + } + + timevar_start (TV_MODULE_IMPORT); + unsigned ident = import_entity_index (decl); + if (pendset *set = pending_table->get (~ident, true)) + { + function_depth++; /* Prevent GC */ + unsigned n = dump.push (NULL); + dump () && dump ("Reading %u pending members keyed to %M[%u] %N", + set->num, import_entity_module (ident), + ident - import_entity_module (ident)->entity_lwm, decl); + pendset_lazy_load (set, false); + dump.pop (n); + + function_depth--; + } + timevar_stop (TV_MODULE_IMPORT); +} + +static void +direct_import (module_state *import, cpp_reader *reader) +{ + timevar_start (TV_MODULE_IMPORT); + unsigned n = dump.push (import); + + gcc_checking_assert (import->is_direct () && import->is_rooted ()); + if (import->loadedness == ML_NONE) + if (!import->do_import (reader, true)) + gcc_unreachable (); + + if (import->loadedness < ML_LANGUAGE) + { + if (!attached_table) + attached_table = new attachset::hash (EXPERIMENT (1, 400)); + import->read_language (true); + } + + (*modules)[0]->set_import (import, import->exported_p); + + dump.pop (n); + timevar_stop (TV_MODULE_IMPORT); +} + +/* Import module IMPORT. */ + +void +import_module (module_state *import, location_t from_loc, bool exporting_p, + tree, cpp_reader *reader) +{ + if (!import->check_not_purview (from_loc)) + return; + + if (!import->is_header () && current_lang_depth ()) + /* Only header units should appear inside language + specifications. The std doesn't specify this, but I think + that's an error in resolving US 033, because language linkage + is also our escape clause to getting things into the global + module, so we don't want to confuse things by having to think + about whether 'extern "C++" { import foo; }' puts foo's + contents into the global module all of a sudden. */ + warning (0, "import of named module %qs inside language-linkage block", + import->get_flatname ()); + + if (exporting_p || module_exporting_p ()) + import->exported_p = true; + + if (import->loadedness != ML_NONE) + { + from_loc = ordinary_loc_of (line_table, from_loc); + linemap_module_reparent (line_table, import->loc, from_loc); + } + gcc_checking_assert (!import->module_p); + gcc_checking_assert (import->is_direct () && import->is_rooted ()); + + direct_import (import, reader); +} + +/* Declare the name of the current module to be NAME. EXPORTING_p is + true if this TU is the exporting module unit. */ + +void +declare_module (module_state *module, location_t from_loc, bool exporting_p, + tree, cpp_reader *reader) +{ + gcc_assert (global_namespace == current_scope ()); + + module_state *current = (*modules)[0]; + if (module_purview_p () || module->loadedness != ML_NONE) + { + error_at (from_loc, module_purview_p () + ? G_("module already declared") + : G_("module already imported")); + if (module_purview_p ()) + module = current; + inform (module->loc, module_purview_p () + ? G_("module %qs declared here") + : G_("module %qs imported here"), + module->get_flatname ()); + return; + } + + gcc_checking_assert (module->module_p); + gcc_checking_assert (module->is_direct () && module->is_rooted ()); + + /* Yer a module, 'arry. */ + module_kind &= ~MK_GLOBAL; + module_kind |= MK_MODULE; + + if (module->is_partition () || exporting_p) + { + gcc_checking_assert (module->get_flatname ()); + + if (module->is_partition ()) + module_kind |= MK_PARTITION; + + if (exporting_p) + { + module->interface_p = true; + module_kind |= MK_INTERFACE; + } + + if (module->is_header ()) + module_kind |= MK_GLOBAL | MK_EXPORTING; + + /* Copy the importing information we may have already done. We + do not need to separate out the imports that only happen in + the GMF, inspite of what the literal wording of the std + might imply. See p2191, the core list had a discussion + where the module implementors agreed that the GMF of a named + module is invisible to importers. */ + module->imports = current->imports; + + module->mod = 0; + (*modules)[0] = module; + } + else + { + module->interface_p = true; + current->parent = module; /* So mangler knows module identity. */ + direct_import (module, reader); + } +} + +/* +1, we're the primary or a partition. Therefore emitting a + globally-callable idemportent initializer function. + -1, we have direct imports. Therefore emitting calls to their + initializers. */ + +int +module_initializer_kind () +{ + int result = 0; + + if (module_has_cmi_p () && !header_module_p ()) + result = +1; + else if (num_init_calls_needed) + result = -1; + + return result; +} + +/* Emit calls to each direct import's global initializer. Including + direct imports of directly imported header units. The initializers + of (static) entities in header units will be called by their + importing modules (for the instance contained within that), or by + the current TU (for the instances we've brought in). Of course + such header unit behaviour is evil, but iostream went through that + door some time ago. */ + +void +module_add_import_initializers () +{ + unsigned calls = 0; + if (modules) + { + tree fntype = build_function_type (void_type_node, void_list_node); + releasing_vec args; // There are no args + + for (unsigned ix = modules->length (); --ix;) + { + module_state *import = (*modules)[ix]; + if (import->call_init_p) + { + tree name = mangle_module_global_init (ix); + tree fndecl = build_lang_decl (FUNCTION_DECL, name, fntype); + + DECL_CONTEXT (fndecl) = FROB_CONTEXT (global_namespace); + SET_DECL_ASSEMBLER_NAME (fndecl, name); + TREE_PUBLIC (fndecl) = true; + determine_visibility (fndecl); + + tree call = cp_build_function_call_vec (fndecl, &args, + tf_warning_or_error); + finish_expr_stmt (call); + + calls++; + } + } + } + + gcc_checking_assert (calls == num_init_calls_needed); +} + +/* NAME & LEN are a preprocessed header name, possibly including the + surrounding "" or <> characters. Return the raw string name of the + module to which it refers. This will be an absolute path, or begin + with ./, so it is immediately distinguishable from a (non-header + unit) module name. If READER is non-null, ask the preprocessor to + locate the header to which it refers using the appropriate include + path. Note that we do never do \ processing of the string, as that + matches the preprocessor's behaviour. */ + +static const char * +canonicalize_header_name (cpp_reader *reader, location_t loc, bool unquoted, + const char *str, size_t &len_r) +{ + size_t len = len_r; + static char *buf = 0; + static size_t alloc = 0; + + if (!unquoted) + { + gcc_checking_assert (len >= 2 + && ((reader && str[0] == '<' && str[len-1] == '>') + || (str[0] == '"' && str[len-1] == '"'))); + str += 1; + len -= 2; + } + + if (reader) + { + gcc_assert (!unquoted); + + if (len >= alloc) + { + alloc = len + 1; + buf = XRESIZEVEC (char, buf, alloc); + } + memcpy (buf, str, len); + buf[len] = 0; + + if (const char *hdr + = cpp_find_header_unit (reader, buf, str[-1] == '<', loc)) + { + len = strlen (hdr); + str = hdr; + } + else + str = buf; + } + + if (!(str[0] == '.' ? IS_DIR_SEPARATOR (str[1]) : IS_ABSOLUTE_PATH (str))) + { + /* Prepend './' */ + if (len + 3 > alloc) + { + alloc = len + 3; + buf = XRESIZEVEC (char, buf, alloc); + } + + buf[0] = '.'; + buf[1] = DIR_SEPARATOR; + memmove (buf + 2, str, len); + len += 2; + buf[len] = 0; + str = buf; + } + + len_r = len; + return str; +} + +/* Set the CMI name from a cody packet. Issue an error if + ill-formed. */ + +void module_state::set_filename (const Cody::Packet &packet) +{ + gcc_checking_assert (!filename); + if (packet.GetCode () == Cody::Client::PC_PATHNAME) + filename = xstrdup (packet.GetString ().c_str ()); + else + { + gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR); + error_at (loc, "unknown Compiled Module Interface: %s", + packet.GetString ().c_str ()); + } +} + +/* Figure out whether to treat HEADER as an include or an import. */ + +static char * +maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, + const char *path) +{ + if (!modules_p ()) + { + /* Turn off. */ + cpp_get_callbacks (reader)->translate_include = NULL; + return nullptr; + } + + if (!spans.init_p ()) + /* Before the main file, don't divert. */ + return nullptr; + + dump.push (NULL); + + dump () && dump ("Checking include translation '%s'", path); + auto *mapper = get_mapper (cpp_main_loc (reader)); + + size_t len = strlen (path); + path = canonicalize_header_name (NULL, loc, true, path, len); + auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len); + int xlate = false; + if (packet.GetCode () == Cody::Client::PC_BOOL) + xlate = -int (packet.GetInteger ()); + else if (packet.GetCode () == Cody::Client::PC_PATHNAME) + { + /* Record the CMI name for when we do the import. */ + module_state *import = get_module (build_string (len, path)); + import->set_filename (packet); + xlate = +1; + } + else + { + gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR); + error_at (loc, "cannot determine %<#include%> translation of %s: %s", + path, packet.GetString ().c_str ()); + } + + bool note = false; + if (note_include_translate_yes && xlate > 1) + note = true; + else if (note_include_translate_no && xlate == 0) + note = true; + else if (note_includes) + { + /* We do not expect the note_includes vector to be large, so O(N) + iteration. */ + for (unsigned ix = note_includes->length (); !note && ix--;) + { + const char *hdr = (*note_includes)[ix]; + size_t hdr_len = strlen (hdr); + if ((hdr_len == len + || (hdr_len < len && IS_DIR_SEPARATOR (path[len - hdr_len - 1]))) + && !memcmp (hdr, path + len - hdr_len, hdr_len)) + note = true; + } + } + + if (note) + inform (loc, xlate + ? G_("include %qs translated to import") + : G_("include %qs processed textually") , path); + + dump () && dump (xlate ? "Translating include to import" + : "Keeping include as include"); + dump.pop (0); + + if (!(xlate > 0)) + return nullptr; + + /* Create the translation text. */ + loc = ordinary_loc_of (lmaps, loc); + const line_map_ordinary *map + = linemap_check_ordinary (linemap_lookup (lmaps, loc)); + unsigned col = SOURCE_COLUMN (map, loc); + col -= (col != 0); /* Columns are 1-based. */ + + unsigned alloc = len + col + 60; + char *res = XNEWVEC (char, alloc); + + strcpy (res, "__import"); + unsigned actual = 8; + if (col > actual) + { + /* Pad out so the filename appears at the same position. */ + memset (res + actual, ' ', col - actual); + actual = col; + } + /* No need to encode characters, that's not how header names are + handled. */ + actual += snprintf (res + actual, alloc - actual, + "\"%s\" [[__translated]];\n", path); + gcc_checking_assert (actual < alloc); + + /* cpplib will delete the buffer. */ + return res; +} + +static void +begin_header_unit (cpp_reader *reader) +{ + /* Set the module header name from the main_input_filename. */ + const char *main = main_input_filename; + size_t len = strlen (main); + main = canonicalize_header_name (NULL, 0, true, main, len); + module_state *module = get_module (build_string (len, main)); + + preprocess_module (module, cpp_main_loc (reader), false, false, true, reader); +} + +/* We've just properly entered the main source file. I.e. after the + command line, builtins and forced headers. Record the line map and + location of this map. Note we may be called more than once. The + first call sticks. */ + +void +module_begin_main_file (cpp_reader *reader, line_maps *lmaps, + const line_map_ordinary *map) +{ + gcc_checking_assert (lmaps == line_table); + if (modules_p () && !spans.init_p ()) + { + unsigned n = dump.push (NULL); + spans.init (lmaps, map); + dump.pop (n); + if (flag_header_unit && !cpp_get_options (reader)->preprocessed) + { + /* Tell the preprocessor this is an include file. */ + cpp_retrofit_as_include (reader); + begin_header_unit (reader); + } + } +} + +/* We've just lexed a module-specific control line for MODULE. Mark + the module as a direct import, and possibly load up its macro + state. Returns the primary module, if this is a module + declaration. */ +/* Perhaps we should offer a preprocessing mode where we read the + directives from the header unit, rather than require the header's + CMI. */ + +module_state * +preprocess_module (module_state *module, location_t from_loc, + bool in_purview, bool is_import, bool is_export, + cpp_reader *reader) +{ + if (!is_import) + { + if (module->loc) + /* It's already been mentioned, so ignore its module-ness. */ + is_import = true; + else + { + /* Record it is the module. */ + module->module_p = true; + if (is_export) + { + module->exported_p = true; + module->interface_p = true; + } + } + } + + if (module->directness < MD_DIRECT + in_purview) + { + /* Mark as a direct import. */ + module->directness = module_directness (MD_DIRECT + in_purview); + + /* Set the location to be most informative for users. */ + from_loc = ordinary_loc_of (line_table, from_loc); + if (module->loadedness != ML_NONE) + linemap_module_reparent (line_table, module->loc, from_loc); + else + { + module->loc = from_loc; + if (!module->flatname) + module->set_flatname (); + } + } + + if (is_import + && !module->is_module () && module->is_header () + && module->loadedness < ML_PREPROCESSOR + && (!cpp_get_options (reader)->preprocessed + || cpp_get_options (reader)->directives_only)) + { + timevar_start (TV_MODULE_IMPORT); + unsigned n = dump.push (module); + + if (module->loadedness == ML_NONE) + { + unsigned pre_hwm = 0; + + /* Preserve the state of the line-map. */ + pre_hwm = LINEMAPS_ORDINARY_USED (line_table); + /* We only need to close the span, if we're going to emit a + CMI. But that's a little tricky -- our token scanner + needs to be smarter -- and this isn't much state. + Remember, we've not parsed anything at this point, so + our module state flags are inadequate. */ + spans.maybe_init (); + spans.close (); + + if (!module->filename) + { + auto *mapper = get_mapper (cpp_main_loc (reader)); + auto packet = mapper->ModuleImport (module->get_flatname ()); + module->set_filename (packet); + } + module->do_import (reader, true); + + /* Restore the line-map state. */ + linemap_module_restore (line_table, pre_hwm); + spans.open (); + } + + if (module->loadedness < ML_PREPROCESSOR) + if (module->read_preprocessor (true)) + module->import_macros (); + + dump.pop (n); + timevar_stop (TV_MODULE_IMPORT); + } + + return is_import ? NULL : get_primary (module); +} + +/* We've completed phase-4 translation. Emit any dependency + information for the not-yet-loaded direct imports, and fill in + their file names. We'll have already loaded up the direct header + unit wavefront. */ + +void +preprocessed_module (cpp_reader *reader) +{ + auto *mapper = get_mapper (cpp_main_loc (reader)); + + spans.maybe_init (); + spans.close (); + + /* Stupid GTY doesn't grok a typedef here. And using type = is, too + modern. */ +#define iterator hash_table<module_state_hash>::iterator + /* using iterator = hash_table<module_state_hash>::iterator; */ + + /* Walk the module hash, asking for the names of all unknown + direct imports and informing of an export (if that's what we + are). Notice these are emitted even when preprocessing as they + inform the server of dependency edges. */ + timevar_start (TV_MODULE_MAPPER); + + dump.push (NULL); + dump () && dump ("Resolving direct import names"); + + if (!flag_preprocess_only + || bool (mapper->get_flags () & Cody::Flags::NameOnly) + || cpp_get_deps (reader)) + { + mapper->Cork (); + iterator end = modules_hash->end (); + for (iterator iter = modules_hash->begin (); iter != end; ++iter) + { + module_state *module = *iter; + if (module->is_direct () && !module->filename) + { + Cody::Flags flags + = (flag_preprocess_only ? Cody::Flags::None + : Cody::Flags::NameOnly); + + if (module->module_p + && (module->is_partition () || module->exported_p)) + mapper->ModuleExport (module->get_flatname (), flags); + else + mapper->ModuleImport (module->get_flatname (), flags); + } + } + + auto response = mapper->Uncork (); + auto r_iter = response.begin (); + for (iterator iter = modules_hash->begin (); iter != end; ++iter) + { + module_state *module = *iter; + + if (module->is_direct () && !module->filename) + { + Cody::Packet const &p = *r_iter; + ++r_iter; + + module->set_filename (p); + } + } + } + + dump.pop (0); + + timevar_stop (TV_MODULE_MAPPER); + + if (mkdeps *deps = cpp_get_deps (reader)) + { + /* Walk the module hash, informing the dependency machinery. */ + iterator end = modules_hash->end (); + for (iterator iter = modules_hash->begin (); iter != end; ++iter) + { + module_state *module = *iter; + + if (module->is_direct ()) + { + if (module->is_module () + && (module->is_interface () || module->is_partition ())) + deps_add_module_target (deps, module->get_flatname (), + maybe_add_cmi_prefix (module->filename), + module->is_header()); + else + deps_add_module_dep (deps, module->get_flatname ()); + } + } + } + + if (flag_header_unit && !flag_preprocess_only) + { + iterator end = modules_hash->end (); + for (iterator iter = modules_hash->begin (); iter != end; ++iter) + { + module_state *module = *iter; + if (module->is_module ()) + { + declare_module (module, cpp_main_loc (reader), true, NULL, reader); + break; + } + } + } +#undef iterator +} + +/* VAL is a global tree, add it to the global vec if it is + interesting. Add some of its targets, if they too are + interesting. We do not add identifiers, as they can be re-found + via the identifier hash table. There is a cost to the number of + global trees. */ + +static int +maybe_add_global (tree val, unsigned &crc) +{ + int v = 0; + + if (val && !(identifier_p (val) || TREE_VISITED (val))) + { + TREE_VISITED (val) = true; + crc = crc32_unsigned (crc, fixed_trees->length ()); + vec_safe_push (fixed_trees, val); + v++; + + if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPED)) + v += maybe_add_global (TREE_TYPE (val), crc); + if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPE_COMMON)) + v += maybe_add_global (TYPE_NAME (val), crc); + } + + return v; +} + +/* Initialize module state. Create the hash table, determine the + global trees. Create the module for current TU. */ + +void +init_modules (cpp_reader *reader) +{ + /* PCH should not be reachable because of lang-specs, but the + user could have overriden that. */ + if (pch_file) + fatal_error (input_location, + "C++ modules are incompatible with precompiled headers"); + + if (cpp_get_options (reader)->traditional) + fatal_error (input_location, + "C++ modules are incompatible with traditional preprocessing"); + + if (flag_preprocess_only) + { + cpp_options *cpp_opts = cpp_get_options (reader); + if (flag_no_output + || (cpp_opts->deps.style != DEPS_NONE + && !cpp_opts->deps.need_preprocessor_output)) + { + warning (0, flag_dump_macros == 'M' + ? G_("macro debug output may be incomplete with modules") + : G_("module dependencies require preprocessing")); + if (cpp_opts->deps.style != DEPS_NONE) + inform (input_location, "you should use the %<-%s%> option", + cpp_opts->deps.style == DEPS_SYSTEM ? "MD" : "MMD"); + } + } + + /* :: is always exported. */ + DECL_MODULE_EXPORT_P (global_namespace) = true; + + modules_hash = hash_table<module_state_hash>::create_ggc (31); + vec_safe_reserve (modules, 20); + + /* Create module for current TU. */ + module_state *current + = new (ggc_alloc<module_state> ()) module_state (NULL_TREE, NULL, false); + current->mod = 0; + bitmap_set_bit (current->imports, 0); + modules->quick_push (current); + + gcc_checking_assert (!fixed_trees); + + headers = BITMAP_GGC_ALLOC (); + + if (note_includes) + for (unsigned ix = 0; ix != note_includes->length (); ix++) + { + const char *hdr = (*note_includes)[ix]; + size_t len = strlen (hdr); + + bool system = hdr[0] == '<'; + bool user = hdr[0] == '"'; + bool delimed = system || user; + + if (len <= (delimed ? 2 : 0) + || (delimed && hdr[len-1] != (system ? '>' : '"'))) + error ("invalid header name %qs", hdr); + + hdr = canonicalize_header_name (delimed ? reader : NULL, + 0, !delimed, hdr, len); + char *path = XNEWVEC (char, len + 1); + memcpy (path, hdr, len); + path[len+1] = 0; + + (*note_includes)[ix] = path; + } + + dump.push (NULL); + + /* Determine lazy handle bound. */ + { + unsigned limit = 1000; +#if HAVE_GETRLIMIT + struct rlimit rlimit; + if (!getrlimit (RLIMIT_NOFILE, &rlimit)) + { + lazy_hard_limit = (rlimit.rlim_max < 1000000 + ? unsigned (rlimit.rlim_max) : 1000000); + lazy_hard_limit = (lazy_hard_limit > LAZY_HEADROOM + ? lazy_hard_limit - LAZY_HEADROOM : 0); + if (rlimit.rlim_cur < limit) + limit = unsigned (rlimit.rlim_cur); + } +#endif + limit = limit > LAZY_HEADROOM ? limit - LAZY_HEADROOM : 1; + + if (unsigned parm = param_lazy_modules) + { + if (parm <= limit || !lazy_hard_limit || !try_increase_lazy (parm)) + lazy_limit = parm; + } + else + lazy_limit = limit; + } + + if (dump ()) + { + verstr_t ver; + version2string (MODULE_VERSION, ver); + dump ("Source: %s", main_input_filename); + dump ("Compiler: %s", version_string); + dump ("Modules: %s", ver); + dump ("Checking: %s", +#if CHECKING_P + "checking" +#elif ENABLE_ASSERT_CHECKING + "asserting" +#else + "release" +#endif + ); + dump ("Compiled by: " +#ifdef __GNUC__ + "GCC %d.%d, %s", __GNUC__, __GNUC_MINOR__, +#ifdef __OPTIMIZE__ + "optimizing" +#else + "not optimizing" +#endif +#else + "not GCC" +#endif + ); + dump ("Reading: %s", MAPPED_READING ? "mmap" : "fileio"); + dump ("Writing: %s", MAPPED_WRITING ? "mmap" : "fileio"); + dump ("Lazy limit: %u", lazy_limit); + dump ("Lazy hard limit: %u", lazy_hard_limit); + dump (""); + } + + /* Construct the global tree array. This is an array of unique + global trees (& types). Do this now, rather than lazily, as + some global trees are lazily created and we don't want that to + mess with our syndrome of fixed trees. */ + unsigned crc = 0; + vec_alloc (fixed_trees, 200); + + dump () && dump ("+Creating globals"); + /* Insert the TRANSLATION_UNIT_DECL. */ + TREE_VISITED (DECL_CONTEXT (global_namespace)) = true; + fixed_trees->quick_push (DECL_CONTEXT (global_namespace)); + for (unsigned jx = 0; global_tree_arys[jx].first; jx++) + { + const tree *ptr = global_tree_arys[jx].first; + unsigned limit = global_tree_arys[jx].second; + + for (unsigned ix = 0; ix != limit; ix++, ptr++) + { + !(ix & 31) && dump ("") && dump ("+\t%u:%u:", jx, ix); + unsigned v = maybe_add_global (*ptr, crc); + dump () && dump ("+%u", v); + } + } + global_crc = crc32_unsigned (crc, fixed_trees->length ()); + dump ("") && dump ("Created %u unique globals, crc=%x", + fixed_trees->length (), global_crc); + for (unsigned ix = fixed_trees->length (); ix--;) + TREE_VISITED ((*fixed_trees)[ix]) = false; + + dump.pop (0); + + if (!flag_module_lazy) + /* Get the mapper now, if we're not being lazy. */ + get_mapper (cpp_main_loc (reader)); + + if (!flag_preprocess_only) + { + pending_table = new pendset::hash (EXPERIMENT (1, 400)); + + entity_map = new entity_map_t (EXPERIMENT (1, 400)); + vec_safe_reserve (entity_ary, EXPERIMENT (1, 400)); + } + +#if CHECKING_P + note_defs = note_defs_table_t::create_ggc (1000); +#endif + + if (flag_header_unit && cpp_get_options (reader)->preprocessed) + begin_header_unit (reader); + + /* Collect here to make sure things are tagged correctly (when + aggressively GC'd). */ + ggc_collect (); +} + +/* If NODE is a deferred macro, load it. */ + +static int +load_macros (cpp_reader *reader, cpp_hashnode *node, void *) +{ + location_t main_loc + = MAP_START_LOCATION (LINEMAPS_ORDINARY_MAP_AT (line_table, 0)); + + if (cpp_user_macro_p (node) + && !node->value.macro) + { + cpp_macro *macro = cpp_get_deferred_macro (reader, node, main_loc); + dump () && dump ("Loaded macro #%s %I", + macro ? "define" : "undef", identifier (node)); + } + + return 1; +} + +/* At the end of tokenizing, we no longer need the macro tables of + imports. But the user might have requested some checking. */ + +void +maybe_check_all_macros (cpp_reader *reader) +{ + if (!warn_imported_macros) + return; + + /* Force loading of any remaining deferred macros. This will + produce diagnostics if they are ill-formed. */ + unsigned n = dump.push (NULL); + cpp_forall_identifiers (reader, load_macros, NULL); + dump.pop (n); +} + +/* Write the CMI, if we're a module interface. */ + +void +finish_module_processing (cpp_reader *reader) +{ + if (header_module_p ()) + module_kind &= ~MK_EXPORTING; + + if (!modules || !(*modules)[0]->name) + { + if (flag_module_only) + warning (0, "%<-fmodule-only%> used for non-interface"); + } + else if (!flag_syntax_only) + { + int fd = -1; + int e = ENOENT; + + timevar_start (TV_MODULE_EXPORT); + + /* Force a valid but empty line map at the end. This simplifies + the line table preparation and writing logic. */ + linemap_add (line_table, LC_ENTER, false, "", 0); + + /* We write to a tmpname, and then atomically rename. */ + const char *path = NULL; + char *tmp_name = NULL; + module_state *state = (*modules)[0]; + + unsigned n = dump.push (state); + state->announce ("creating"); + if (state->filename) + { + size_t len = 0; + path = maybe_add_cmi_prefix (state->filename, &len); + tmp_name = XNEWVEC (char, len + 3); + memcpy (tmp_name, path, len); + strcpy (&tmp_name[len], "~"); + + if (!errorcount) + for (unsigned again = 2; ; again--) + { + fd = open (tmp_name, + O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + e = errno; + if (fd >= 0 || !again || e != ENOENT) + break; + create_dirs (tmp_name); + } + dump () && dump ("CMI is %s", path); + } + + if (errorcount) + warning_at (state->loc, 0, "not writing module %qs due to errors", + state->get_flatname ()); + else + { + elf_out to (fd, e); + if (to.begin ()) + { + auto loc = input_location; + /* So crashes finger point the module decl. */ + input_location = state->loc; + state->write (&to, reader); + input_location = loc; + } + if (to.end ()) + { + /* Some OS's do not replace NEWNAME if it already + exists. This'll have a race condition in erroneous + concurrent builds. */ + unlink (path); + if (rename (tmp_name, path)) + { + dump () && dump ("Rename ('%s','%s') errno=%u", errno); + to.set_error (errno); + } + } + + if (to.get_error ()) + { + error_at (state->loc, "failed to write compiled module: %s", + to.get_error (state->filename)); + state->note_cmi_name (); + } + } + + if (!errorcount) + { + auto *mapper = get_mapper (cpp_main_loc (reader)); + + mapper->ModuleCompiled (state->get_flatname ()); + } + else if (path) + { + /* We failed, attempt to erase all evidence we even tried. */ + unlink (tmp_name); + unlink (path); + XDELETEVEC (tmp_name); + } + + dump.pop (n); + timevar_stop (TV_MODULE_EXPORT); + + ggc_collect (); + } + + if (modules) + { + unsigned n = dump.push (NULL); + dump () && dump ("Imported %u modules", modules->length () - 1); + dump () && dump ("Containing %u clusters", available_clusters); + dump () && dump ("Loaded %u clusters (%u%%)", loaded_clusters, + (loaded_clusters * 100 + available_clusters / 2) / + (available_clusters + !available_clusters)); + dump.pop (n); + } + + if (modules && !header_module_p ()) + { + /* Determine call_init_p. We need the same bitmap allocation + scheme as for the imports member. */ + function_depth++; /* Disable GC. */ + bitmap indirect_imports (BITMAP_GGC_ALLOC ()); + + /* Because indirect imports are before their direct import, and + we're scanning the array backwards, we only need one pass! */ + for (unsigned ix = modules->length (); --ix;) + { + module_state *import = (*modules)[ix]; + + if (!import->is_header () + && !bitmap_bit_p (indirect_imports, ix)) + { + /* Everything this imports is therefore indirectly + imported. */ + bitmap_ior_into (indirect_imports, import->imports); + /* We don't have to worry about the self-import bit, + because of the single pass. */ + + import->call_init_p = true; + num_init_calls_needed++; + } + } + function_depth--; + } +} + +void +fini_modules () +{ + /* We're done with the macro tables now. */ + vec_free (macro_exports); + vec_free (macro_imports); + headers = NULL; + + /* We're now done with everything but the module names. */ + set_cmi_repo (NULL); + if (mapper) + { + timevar_start (TV_MODULE_MAPPER); + module_client::close_module_client (0, mapper); + mapper = nullptr; + timevar_stop (TV_MODULE_MAPPER); + } + module_state_config::release (); + +#if CHECKING_P + note_defs = NULL; +#endif + + if (modules) + for (unsigned ix = modules->length (); --ix;) + if (module_state *state = (*modules)[ix]) + state->release (); + + /* No need to lookup modules anymore. */ + modules_hash = NULL; + + /* Or entity array. We still need the entity map to find import numbers. */ + delete entity_ary; + entity_ary = NULL; + + /* Or remember any pending entities. */ + delete pending_table; + pending_table = NULL; + + /* Or any attachments -- Let it go! */ + delete attached_table; + attached_table = NULL; + + /* Allow a GC, we've possibly made much data unreachable. */ + ggc_collect (); +} + +/* If CODE is a module option, handle it & return true. Otherwise + return false. For unknown reasons I cannot get the option + generation machinery to set fmodule-mapper or -fmodule-header to + make a string type option variable. */ + +bool +handle_module_option (unsigned code, const char *str, int) +{ + auto hdr = CMS_header; + + switch (opt_code (code)) + { + case OPT_fmodule_mapper_: + module_mapper_name = str; + return true; + + case OPT_fmodule_header_: + { + if (!strcmp (str, "user")) + hdr = CMS_user; + else if (!strcmp (str, "system")) + hdr = CMS_system; + else + error ("unknown header kind %qs", str); + } + /* Fallthrough. */ + + case OPT_fmodule_header: + flag_header_unit = hdr; + flag_modules = 1; + return true; + + case OPT_flang_info_include_translate_: + vec_safe_push (note_includes, str); + return true; + + default: + return false; + } +} + +/* Set preprocessor callbacks and options for modules. */ + +void +module_preprocess_options (cpp_reader *reader) +{ + gcc_checking_assert (!lang_hooks.preprocess_undef); + if (modules_p ()) + { + auto *cb = cpp_get_callbacks (reader); + + cb->translate_include = maybe_translate_include; + cb->user_deferred_macro = module_state::deferred_macro; + if (flag_header_unit) + { + /* If the preprocessor hook is already in use, that + implementation will call the undef langhook. */ + if (cb->undef) + lang_hooks.preprocess_undef = module_state::undef_macro; + else + cb->undef = module_state::undef_macro; + } + auto *opt = cpp_get_options (reader); + opt->module_directives = true; + opt->main_search = cpp_main_search (flag_header_unit); + } +} + +#include "gt-cp-module.h" diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index c87d151..52e4a63 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1,5 +1,5 @@ /* Definitions for C++ name lookup routines. - Copyright (C) 2003-2020 Free Software Foundation, Inc. + Copyright (C) 2003-2021 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> This file is part of GCC. @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/name-hint.h" #include "c-family/known-headers.h" #include "c-family/c-spellcheck.h" +#include "bitmap.h" static cxx_binding *cxx_binding_make (tree value, tree type); static cp_binding_level *innermost_nonclass_level (void); @@ -46,16 +47,33 @@ static name_hint maybe_suggest_missing_std_header (location_t location, static name_hint suggest_alternatives_for_1 (location_t location, tree name, bool suggest_misspellings); +/* Slots in BINDING_VECTOR. */ +enum binding_slots +{ + BINDING_SLOT_CURRENT, /* Slot for current TU. */ + BINDING_SLOT_GLOBAL, /* Slot for merged global module. */ + BINDING_SLOT_PARTITION, /* Slot for merged partition entities + (optional). */ + + /* Number of always-allocated slots. */ + BINDING_SLOTS_FIXED = BINDING_SLOT_GLOBAL + 1 +}; + /* Create an overload suitable for recording an artificial TYPE_DECL and another decl. We use this machanism to implement the struct - stat hack within a namespace. It'd be nice to use it everywhere. */ + stat hack. */ #define STAT_HACK_P(N) ((N) && TREE_CODE (N) == OVERLOAD && OVL_LOOKUP_P (N)) +#define STAT_TYPE_VISIBLE_P(N) TREE_USED (OVERLOAD_CHECK (N)) #define STAT_TYPE(N) TREE_TYPE (N) #define STAT_DECL(N) OVL_FUNCTION (N) +#define STAT_VISIBLE(N) OVL_CHAIN (N) #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) +/* When a STAT_HACK_P is true, OVL_USING_P and OVL_EXPORT_P are valid + and apply to the hacked type. */ + /* 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 @@ -116,7 +134,246 @@ find_namespace_value (tree ns, tree name) return b ? MAYBE_STAT_DECL (*b) : NULL_TREE; } -/* Add DECL to the list of things declared in B. */ +/* Look in *SLOT for a the binding of NAME in imported module IX. + Returns pointer to binding's slot, or NULL if not found. Does a + binary search, as this is mainly used for random access during + importing. Do not use for the fixed slots. */ + +static binding_slot * +search_imported_binding_slot (tree *slot, unsigned ix) +{ + gcc_assert (ix); + + if (!*slot) + return NULL; + + if (TREE_CODE (*slot) != BINDING_VECTOR) + return NULL; + + unsigned clusters = BINDING_VECTOR_NUM_CLUSTERS (*slot); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (*slot); + + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + clusters--; + cluster++; + } + + while (clusters > 1) + { + unsigned half = clusters / 2; + gcc_checking_assert (cluster[half].indices[0].span); + if (cluster[half].indices[0].base > ix) + clusters = half; + else + { + clusters -= half; + cluster += half; + } + } + + if (clusters) + /* Is it in this cluster? */ + for (unsigned off = 0; off != BINDING_VECTOR_SLOTS_PER_CLUSTER; off++) + { + if (!cluster->indices[off].span) + break; + if (cluster->indices[off].base > ix) + break; + + if (cluster->indices[off].base + cluster->indices[off].span > ix) + return &cluster->slots[off]; + } + + return NULL; +} + +static void +init_global_partition (binding_cluster *cluster, tree decl) +{ + bool purview = true; + + if (header_module_p ()) + purview = false; + else if (TREE_PUBLIC (decl) + && TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl)) + purview = false; + else if (!get_originating_module (decl)) + purview = false; + + binding_slot *mslot; + if (!purview) + mslot = &cluster[0].slots[BINDING_SLOT_GLOBAL]; + else + mslot = &cluster[BINDING_SLOT_PARTITION + / BINDING_VECTOR_SLOTS_PER_CLUSTER] + .slots[BINDING_SLOT_PARTITION + % BINDING_VECTOR_SLOTS_PER_CLUSTER]; + + if (*mslot) + decl = ovl_make (decl, *mslot); + *mslot = decl; + + if (TREE_CODE (decl) == CONST_DECL) + { + tree type = TREE_TYPE (decl); + if (TREE_CODE (type) == ENUMERAL_TYPE + && IDENTIFIER_ANON_P (DECL_NAME (TYPE_NAME (type))) + && decl == TREE_VALUE (TYPE_VALUES (type))) + /* Anonymous enums are keyed by their first enumerator, put + the TYPE_DECL here too. */ + *mslot = ovl_make (TYPE_NAME (type), *mslot); + } +} + +/* Get the fixed binding slot IX. Creating the vector if CREATE is + non-zero. If CREATE is < 0, make sure there is at least 1 spare + slot for an import. (It is an error for CREATE < 0 and the slot to + already exist.) */ + +static tree * +get_fixed_binding_slot (tree *slot, tree name, unsigned ix, int create) +{ + gcc_checking_assert (ix <= BINDING_SLOT_PARTITION); + + /* An assumption is that the fixed slots all reside in one cluster. */ + gcc_checking_assert (BINDING_VECTOR_SLOTS_PER_CLUSTER >= BINDING_SLOTS_FIXED); + + if (!*slot || TREE_CODE (*slot) != BINDING_VECTOR) + { + if (ix == BINDING_SLOT_CURRENT) + /* The current TU can just use slot directly. */ + return slot; + + if (!create) + return NULL; + + /* The partition slot is only needed when we know we're a named + module. */ + bool partition_slot = named_module_p (); + unsigned want = ((BINDING_SLOTS_FIXED + partition_slot + (create < 0) + + BINDING_VECTOR_SLOTS_PER_CLUSTER - 1) + / BINDING_VECTOR_SLOTS_PER_CLUSTER); + tree new_vec = make_binding_vec (name, want); + BINDING_VECTOR_NUM_CLUSTERS (new_vec) = want; + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (new_vec); + + /* Initialize the fixed slots. */ + for (unsigned jx = BINDING_SLOTS_FIXED; jx--;) + { + cluster[0].indices[jx].base = 0; + cluster[0].indices[jx].span = 1; + cluster[0].slots[jx] = NULL_TREE; + } + + if (partition_slot) + { + unsigned off = BINDING_SLOT_PARTITION % BINDING_VECTOR_SLOTS_PER_CLUSTER; + unsigned ind = BINDING_SLOT_PARTITION / BINDING_VECTOR_SLOTS_PER_CLUSTER; + cluster[ind].indices[off].base = 0; + cluster[ind].indices[off].span = 1; + cluster[ind].slots[off] = NULL_TREE; + } + + if (tree orig = *slot) + { + /* Propagate existing value to current slot. */ + + /* Propagate global & module entities to the global and + partition slots. */ + if (tree type = MAYBE_STAT_TYPE (orig)) + init_global_partition (cluster, type); + + for (ovl_iterator iter (MAYBE_STAT_DECL (orig)); iter; ++iter) + { + tree decl = *iter; + + /* Internal linkage entities are in deduplicateable. */ + init_global_partition (cluster, decl); + } + + if (cluster[0].slots[BINDING_SLOT_GLOBAL] + && !(TREE_CODE (orig) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (orig))) + { + /* Note that we had some GMF entries. */ + if (!STAT_HACK_P (orig)) + orig = stat_hack (orig); + + MODULE_BINDING_GLOBAL_P (orig) = true; + } + + cluster[0].slots[BINDING_SLOT_CURRENT] = orig; + } + + *slot = new_vec; + } + else + gcc_checking_assert (create >= 0); + + unsigned off = ix % BINDING_VECTOR_SLOTS_PER_CLUSTER; + binding_cluster &cluster + = BINDING_VECTOR_CLUSTER (*slot, ix / BINDING_VECTOR_SLOTS_PER_CLUSTER); + + /* There must always be slots for these indices */ + gcc_checking_assert (cluster.indices[off].span == 1 + && !cluster.indices[off].base + && !cluster.slots[off].is_lazy ()); + + return reinterpret_cast<tree *> (&cluster.slots[off]); +} + +/* *SLOT is a namespace binding slot. Append a slot for imported + module IX. */ + +static binding_slot * +append_imported_binding_slot (tree *slot, tree name, unsigned ix) +{ + gcc_checking_assert (ix); + + if (!*slot || TREE_CODE (*slot) != BINDING_VECTOR) + /* Make an initial module vector. */ + get_fixed_binding_slot (slot, name, BINDING_SLOT_GLOBAL, -1); + else if (!BINDING_VECTOR_CLUSTER_LAST (*slot) + ->indices[BINDING_VECTOR_SLOTS_PER_CLUSTER - 1].span) + /* There is space in the last cluster. */; + else if (BINDING_VECTOR_NUM_CLUSTERS (*slot) + != BINDING_VECTOR_ALLOC_CLUSTERS (*slot)) + /* There is space in the vector. */ + BINDING_VECTOR_NUM_CLUSTERS (*slot)++; + else + { + /* Extend the vector. */ + unsigned have = BINDING_VECTOR_NUM_CLUSTERS (*slot); + unsigned want = (have * 3 + 1) / 2; + + if (want > (unsigned short)~0) + want = (unsigned short)~0; + + tree new_vec = make_binding_vec (name, want); + BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1; + memcpy (BINDING_VECTOR_CLUSTER_BASE (new_vec), + BINDING_VECTOR_CLUSTER_BASE (*slot), + have * sizeof (binding_cluster)); + *slot = new_vec; + } + + binding_cluster *last = BINDING_VECTOR_CLUSTER_LAST (*slot); + for (unsigned off = 0; off != BINDING_VECTOR_SLOTS_PER_CLUSTER; off++) + if (!last->indices[off].span) + { + /* Fill the free slot of the cluster. */ + last->indices[off].base = ix; + last->indices[off].span = 1; + last->slots[off] = NULL_TREE; + return &last->slots[off]; + } + + gcc_unreachable (); +} + +/* Add DECL to the list of things declared in binding level B. */ static void add_decl_to_level (cp_binding_level *b, tree decl) @@ -243,7 +500,7 @@ private: void add_value (tree new_val); void add_type (tree new_type); bool process_binding (tree val_bind, tree type_bind); - + unsigned process_module_binding (tree val_bind, tree type_bind, unsigned); /* Look in only namespace. */ bool search_namespace_only (tree scope); /* Look in namespace and its (recursive) inlines. Ignore using @@ -278,7 +535,7 @@ private: void adl_class_only (tree); void adl_namespace (tree); void adl_class_fns (tree); - void adl_namespace_fns (tree); + void adl_namespace_fns (tree, bitmap); public: /* Search namespace + inlines + maybe usings as qualified lookup. */ @@ -548,36 +805,190 @@ name_lookup::process_binding (tree new_val, tree new_type) return new_val != NULL_TREE; } +/* If we're importing a module containing this binding, add it to the + lookup set. The trickiness is with namespaces, we only want to + find it once. */ + +unsigned +name_lookup::process_module_binding (tree new_val, tree new_type, + unsigned marker) +{ + /* Optimize for (re-)finding a public namespace. We only need to + look once. */ + if (new_val && !new_type + && TREE_CODE (new_val) == NAMESPACE_DECL + && TREE_PUBLIC (new_val) + && !DECL_NAMESPACE_ALIAS (new_val)) + { + if (marker & 2) + return marker; + marker |= 2; + } + + if (new_type || new_val) + marker |= process_binding (new_val, new_type); + + return marker; +} + /* Look in exactly namespace SCOPE. */ bool name_lookup::search_namespace_only (tree scope) { bool found = false; - if (tree *binding = find_namespace_slot (scope, name)) { - tree value = *binding, type = NULL_TREE; - - if (STAT_HACK_P (value)) + tree val = *binding; + if (TREE_CODE (val) == BINDING_VECTOR) { - type = STAT_TYPE (value); - value = STAT_DECL (value); - - if (!bool (want & LOOK_want::HIDDEN_FRIEND)) + /* I presume the binding list is going to be sparser than + the import bitmap. Hence iterate over the former + checking for bits set in the bitmap. */ + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (val); + int marker = 0; + int dup_detect = 0; + + if (tree bind = cluster->slots[BINDING_SLOT_CURRENT]) { - if (STAT_TYPE_HIDDEN_P (*binding)) - type = NULL_TREE; - if (STAT_DECL_HIDDEN_P (*binding)) - value = NULL_TREE; - else + if (!deduping) + { + if (named_module_purview_p ()) + { + dup_detect |= 2; + + if (STAT_HACK_P (bind) && MODULE_BINDING_GLOBAL_P (bind)) + dup_detect |= 1; + } + else + dup_detect |= 1; + } + tree type = NULL_TREE; + tree value = bind; + + if (STAT_HACK_P (bind)) + { + type = STAT_TYPE (bind); + value = STAT_DECL (bind); + + if (!bool (want & LOOK_want::HIDDEN_FRIEND)) + { + if (STAT_TYPE_HIDDEN_P (bind)) + type = NULL_TREE; + if (STAT_DECL_HIDDEN_P (bind)) + value = NULL_TREE; + else + value = ovl_skip_hidden (value); + } + } + else if (!bool (want & LOOK_want::HIDDEN_FRIEND)) value = ovl_skip_hidden (value); + + marker = process_module_binding (value, type, marker); } + + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (val); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + + /* Do this in forward order, so we load modules in an order + the user expects. */ + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Are we importing this module? */ + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (imports, base)) + goto found; + while (++base, --span); + continue; + + found:; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + { + gcc_assert (cluster->indices[jx].span == 1); + lazy_load_binding (cluster->indices[jx].base, + scope, name, &cluster->slots[jx]); + } + tree bind = cluster->slots[jx]; + if (!bind) + /* Load errors could mean there's nothing here. */ + continue; + + /* Extract what we can see from here. If there's no + stat_hack, then everything was exported. */ + tree type = NULL_TREE; + + + /* If STAT_HACK_P is false, everything is visible, and + there's no duplication possibilities. */ + if (STAT_HACK_P (bind)) + { + if (!deduping) + { + /* Do we need to engage deduplication? */ + int dup = 0; + if (MODULE_BINDING_GLOBAL_P (bind)) + dup = 1; + else if (MODULE_BINDING_PARTITION_P (bind)) + dup = 2; + if (unsigned hit = dup_detect & dup) + { + if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) + || (hit & 2 + && BINDING_VECTOR_PARTITION_DUPS_P (val))) + { + lookup_mark (value, true); + deduping = true; + } + } + dup_detect |= dup; + } + + if (STAT_TYPE_VISIBLE_P (bind)) + type = STAT_TYPE (bind); + bind = STAT_VISIBLE (bind); + } + + /* And process it. */ + marker = process_module_binding (bind, type, marker); + } + found |= marker & 1; } - else if (!bool (want & LOOK_want::HIDDEN_FRIEND)) - value = ovl_skip_hidden (value); + else + { + /* Only a current module binding, visible from the current module. */ + tree bind = *binding; + tree value = bind, type = NULL_TREE; + + if (STAT_HACK_P (bind)) + { + type = STAT_TYPE (bind); + value = STAT_DECL (bind); + + if (!bool (want & LOOK_want::HIDDEN_FRIEND)) + { + if (STAT_TYPE_HIDDEN_P (bind)) + type = NULL_TREE; + if (STAT_DECL_HIDDEN_P (bind)) + 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); + found |= process_binding (value, type); + } } return found; @@ -788,12 +1199,103 @@ name_lookup::add_fns (tree fns) /* Add the overloaded fns of SCOPE. */ void -name_lookup::adl_namespace_fns (tree scope) +name_lookup::adl_namespace_fns (tree scope, bitmap imports) { if (tree *binding = find_namespace_slot (scope, name)) { tree val = *binding; - add_fns (ovl_skip_hidden (MAYBE_STAT_DECL (val))); + if (TREE_CODE (val) != BINDING_VECTOR) + add_fns (ovl_skip_hidden (MAYBE_STAT_DECL (val))); + else + { + /* I presume the binding list is going to be sparser than + the import bitmap. Hence iterate over the former + checking for bits set in the bitmap. */ + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (val); + int dup_detect = 0; + + if (tree bind = cluster->slots[BINDING_SLOT_CURRENT]) + { + /* The current TU's bindings must be visible, we don't + need to check the bitmaps. */ + + if (!deduping) + { + if (named_module_purview_p ()) + { + dup_detect |= 2; + + if (STAT_HACK_P (bind) && MODULE_BINDING_GLOBAL_P (bind)) + dup_detect |= 1; + } + else + dup_detect |= 1; + } + + add_fns (ovl_skip_hidden (MAYBE_STAT_DECL (bind))); + } + + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (val); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + + /* Do this in forward order, so we load modules in an order + the user expects. */ + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Functions are never on merged slots. */ + if (!cluster->indices[jx].base + || cluster->indices[jx].span != 1) + continue; + + /* Is this slot visible? */ + if (!bitmap_bit_p (imports, cluster->indices[jx].base)) + continue; + + /* Is it loaded. */ + if (cluster->slots[jx].is_lazy ()) + lazy_load_binding (cluster->indices[jx].base, + scope, name, &cluster->slots[jx]); + + tree bind = cluster->slots[jx]; + if (!bind) + /* Load errors could mean there's nothing here. */ + continue; + + if (STAT_HACK_P (bind)) + { + if (!deduping) + { + /* Do we need to engage deduplication? */ + int dup = 0; + if (MODULE_BINDING_GLOBAL_P (bind)) + dup = 1; + else if (MODULE_BINDING_PARTITION_P (bind)) + dup = 2; + if (unsigned hit = dup_detect & dup) + { + if ((hit & 1 && BINDING_VECTOR_GLOBAL_DUPS_P (val)) + || (hit & 2 + && BINDING_VECTOR_PARTITION_DUPS_P (val))) + { + lookup_mark (value, true); + deduping = true; + } + } + dup_detect |= dup; + } + + bind = STAT_VISIBLE (bind); + } + + add_fns (bind); + } + } } } @@ -1133,13 +1635,77 @@ name_lookup::search_adl (tree fns, vec<tree, va_gc> *args) } value = fns; + /* INST_PATH will be NULL, if this is /not/ 2nd-phase ADL. */ + bitmap inst_path = NULL; + /* VISIBLE is the regular import bitmap. */ + bitmap visible = visible_instantiation_path (&inst_path); + for (unsigned ix = scopes->length (); ix--;) { tree scope = (*scopes)[ix]; if (TREE_CODE (scope) == NAMESPACE_DECL) - adl_namespace_fns (scope); - else if (RECORD_OR_UNION_TYPE_P (scope)) - adl_class_fns (scope); + adl_namespace_fns (scope, visible); + else + { + if (RECORD_OR_UNION_TYPE_P (scope)) + adl_class_fns (scope); + + /* During 2nd phase ADL: Any exported declaration D in N + declared within the purview of a named module M + (10.2) is visible if there is an associated entity + attached to M with the same innermost enclosing + non-inline namespace as D. + [basic.lookup.argdep]/4.4 */ + + if (!inst_path) + /* Not 2nd phase. */ + continue; + + tree ctx = CP_DECL_CONTEXT (TYPE_NAME (scope)); + if (TREE_CODE (ctx) != NAMESPACE_DECL) + /* Not namespace-scope class. */ + continue; + + tree origin = get_originating_module_decl (TYPE_NAME (scope)); + if (!DECL_LANG_SPECIFIC (origin) + || !DECL_MODULE_IMPORT_P (origin)) + /* Not imported. */ + continue; + + unsigned module = get_importing_module (origin); + + if (!bitmap_bit_p (inst_path, module)) + /* Not on path of instantiation. */ + continue; + + if (bitmap_bit_p (visible, module)) + /* If the module was in the visible set, we'll look at + its namespace partition anyway. */ + continue; + + if (tree *slot = find_namespace_slot (ctx, name, false)) + if (binding_slot *mslot = search_imported_binding_slot (slot, module)) + { + if (mslot->is_lazy ()) + lazy_load_binding (module, ctx, name, mslot); + + if (tree bind = *mslot) + { + if (!deduping) + { + /* We must turn on deduping, because some + other class from this module might also + be in this namespace. */ + deduping = true; + lookup_mark (value, true); + } + + /* Add the exported fns */ + if (STAT_HACK_P (bind)) + add_fns (STAT_VISIBLE (bind)); + } + } + } } fns = value; @@ -1338,6 +1904,41 @@ get_class_binding_direct (tree klass, tree name, bool want_type) return val; } +/* We're about to lookup NAME in KLASS. Make sure any lazily declared + members are now declared. */ + +static void +maybe_lazily_declare (tree klass, tree name) +{ + tree main_decl = TYPE_NAME (TYPE_MAIN_VARIANT (klass)); + if (DECL_LANG_SPECIFIC (main_decl) + && DECL_MODULE_PENDING_MEMBERS_P (main_decl)) + lazy_load_members (main_decl); + + /* Lazily declare functions, if we're going to search these. */ + if (IDENTIFIER_CTOR_P (name)) + { + if (CLASSTYPE_LAZY_DEFAULT_CTOR (klass)) + lazily_declare_fn (sfk_constructor, klass); + if (CLASSTYPE_LAZY_COPY_CTOR (klass)) + lazily_declare_fn (sfk_copy_constructor, klass); + if (CLASSTYPE_LAZY_MOVE_CTOR (klass)) + lazily_declare_fn (sfk_move_constructor, klass); + } + else if (IDENTIFIER_DTOR_P (name)) + { + if (CLASSTYPE_LAZY_DESTRUCTOR (klass)) + lazily_declare_fn (sfk_destructor, klass); + } + else if (name == assign_op_identifier) + { + if (CLASSTYPE_LAZY_COPY_ASSIGN (klass)) + lazily_declare_fn (sfk_copy_assignment, klass); + if (CLASSTYPE_LAZY_MOVE_ASSIGN (klass)) + lazily_declare_fn (sfk_move_assignment, klass); + } +} + /* Look for NAME's binding in exactly KLASS. See get_class_binding_direct for argument description. Does lazy special function creation as necessary. */ @@ -1348,30 +1949,7 @@ get_class_binding (tree klass, tree name, bool want_type /*=false*/) klass = complete_type (klass); if (COMPLETE_TYPE_P (klass)) - { - /* Lazily declare functions, if we're going to search these. */ - if (IDENTIFIER_CTOR_P (name)) - { - if (CLASSTYPE_LAZY_DEFAULT_CTOR (klass)) - lazily_declare_fn (sfk_constructor, klass); - if (CLASSTYPE_LAZY_COPY_CTOR (klass)) - lazily_declare_fn (sfk_copy_constructor, klass); - if (CLASSTYPE_LAZY_MOVE_CTOR (klass)) - lazily_declare_fn (sfk_move_constructor, klass); - } - else if (IDENTIFIER_DTOR_P (name)) - { - if (CLASSTYPE_LAZY_DESTRUCTOR (klass)) - lazily_declare_fn (sfk_destructor, klass); - } - else if (name == assign_op_identifier) - { - if (CLASSTYPE_LAZY_COPY_ASSIGN (klass)) - lazily_declare_fn (sfk_copy_assignment, klass); - if (CLASSTYPE_LAZY_MOVE_ASSIGN (klass)) - lazily_declare_fn (sfk_move_assignment, klass); - } - } + maybe_lazily_declare (klass, name); return get_class_binding_direct (klass, name, want_type); } @@ -1392,14 +1970,11 @@ find_member_slot (tree klass, tree name) vec_alloc (member_vec, 8); CLASSTYPE_MEMBER_VEC (klass) = member_vec; if (complete_p) - { - /* If the class is complete but had no member_vec, we need - to add the TYPE_FIELDS into it. We're also most likely - to be adding ctors & dtors, so ask for 6 spare slots (the - abstract cdtors and their clones). */ - set_class_bindings (klass, 6); - member_vec = CLASSTYPE_MEMBER_VEC (klass); - } + /* If the class is complete but had no member_vec, we need to + add the TYPE_FIELDS into it. We're also most likely to be + adding ctors & dtors, so ask for 6 spare slots (the + abstract cdtors and their clones). */ + member_vec = set_class_bindings (klass, 6); } if (IDENTIFIER_CONV_OP_P (name)) @@ -1741,18 +2316,18 @@ 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 anyway. */ + one field anyway. If EXTRA < 0, always create the vector. */ -void -set_class_bindings (tree klass, unsigned extra) +vec<tree, va_gc> * +set_class_bindings (tree klass, int extra) { unsigned n_fields = count_class_fields (klass); vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass); - if (member_vec || n_fields >= 8) + if (member_vec || n_fields >= 8 || extra < 0) { /* Append the new fields. */ - vec_safe_reserve_exact (member_vec, extra + n_fields); + vec_safe_reserve_exact (member_vec, n_fields + (extra >= 0 ? extra : 0)); member_vec_append_class_fields (member_vec, klass); } @@ -1762,6 +2337,8 @@ set_class_bindings (tree klass, unsigned extra) member_vec->qsort (member_name_cmp); member_vec_dedup (member_vec); } + + return member_vec; } /* Insert lately defined enum ENUMTYPE into KLASS for the sorted case. */ @@ -1910,7 +2487,7 @@ push_binding (tree id, tree decl, cp_binding_level* level) void pop_local_binding (tree id, tree decl) { - if (id == NULL_TREE) + if (!id || IDENTIFIER_ANON_P (id)) /* It's easiest to write the loops that call this function without checking whether or not the entities involved have names. We get here for such an entity. */ @@ -2260,8 +2837,9 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, tree to_type = old_type; bool local_overload = false; - gcc_assert (level->kind == sk_namespace ? !binding + gcc_assert (!level || level->kind == sk_namespace ? !binding : level->kind != sk_class && !slot); + if (old == error_mark_node) old = NULL_TREE; @@ -2337,7 +2915,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, warning (OPT_Wshadow, "%q#D hides constructor for %q#D", decl, to_type); - local_overload = old && level->kind != sk_namespace; + local_overload = old && level && level->kind != sk_namespace; to_val = ovl_insert (decl, old, -int (hiding)); } else if (old) @@ -2348,11 +2926,8 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, 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; - } + /* Two type decls to the same type. Do nothing. */ + return old; else goto conflict; } @@ -2364,7 +2939,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, goto conflict; /* The new one must be an alias at this point. */ - gcc_assert (DECL_NAMESPACE_ALIAS (decl) && !hiding); + gcc_assert (DECL_NAMESPACE_ALIAS (decl)); return old; } else if (TREE_CODE (old) == VAR_DECL) @@ -2399,7 +2974,11 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, gcc_checking_assert (binding->value && OVL_P (binding->value)); update_local_overload (binding, to_val); } - else + else if (level + && !(TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl))) + /* Don't add namespaces here. They're done in + push_namespace. */ add_decl_to_level (level, decl); if (slot) @@ -2905,6 +3484,182 @@ push_local_extern_decl_alias (tree decl) DECL_LOCAL_DECL_ALIAS (decl) = alias; } +/* NS needs to be exported, mark it and all its parents as exported. */ + +static void +implicitly_export_namespace (tree ns) +{ + while (!DECL_MODULE_EXPORT_P (ns)) + { + DECL_MODULE_EXPORT_P (ns) = true; + ns = CP_DECL_CONTEXT (ns); + } +} + +/* DECL has just been bound at LEVEL. finish up the bookkeeping. */ + +static void +newbinding_bookkeeping (tree name, tree decl, cp_binding_level *level) +{ + if (TREE_CODE (decl) == TYPE_DECL) + { + tree type = TREE_TYPE (decl); + + if (type != error_mark_node) + { + if (TYPE_NAME (type) != decl) + set_underlying_type (decl); + + set_identifier_type_value_with_scope (name, decl, level); + + if (level->kind != sk_namespace + && !instantiating_current_function_p ()) + /* This is a locally defined typedef in a function that + is not a template instantation, record it to implement + -Wunused-local-typedefs. */ + record_locally_defined_typedef (decl); + } + } + else + { + if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) + maybe_register_incomplete_var (decl); + + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_EXTERN_C_P (decl)) + check_extern_c_conflict (decl); + } +} + +/* DECL is a global or module-purview entity. If it has non-internal + linkage, and we have a module vector, record it in the appropriate + slot. We have already checked for duplicates. */ + +static void +maybe_record_mergeable_decl (tree *slot, tree name, tree decl) +{ + if (TREE_CODE (*slot) != BINDING_VECTOR) + return; + + if (!TREE_PUBLIC (CP_DECL_CONTEXT (decl))) + /* Member of internal namespace. */ + return; + + tree not_tmpl = STRIP_TEMPLATE (decl); + if ((TREE_CODE (not_tmpl) == FUNCTION_DECL + || TREE_CODE (not_tmpl) == VAR_DECL) + && DECL_THIS_STATIC (not_tmpl)) + /* Internal linkage. */ + return; + + bool partition = named_module_p (); + tree *gslot = get_fixed_binding_slot + (slot, name, partition ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, true); + + if (!partition) + { + binding_slot &orig + = BINDING_VECTOR_CLUSTER (*gslot, 0).slots[BINDING_SLOT_CURRENT]; + + if (!STAT_HACK_P (tree (orig))) + orig = stat_hack (tree (orig)); + + MODULE_BINDING_GLOBAL_P (tree (orig)) = true; + } + + add_mergeable_namespace_entity (gslot, decl); +} + +/* DECL is being pushed. Check whether it hides or ambiguates + something seen as an import. This include decls seen in our own + interface, which is OK. Also, check for merging a + global/partition decl. */ + +static tree +check_module_override (tree decl, tree mvec, bool hiding, + tree scope, tree name) +{ + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (mvec); + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (mvec); + + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + cluster++; + ix--; + } + + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Are we importing this module? */ + if (cluster->indices[jx].span != 1) + continue; + if (!cluster->indices[jx].base) + continue; + if (!bitmap_bit_p (imports, cluster->indices[jx].base)) + continue; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + { + gcc_assert (cluster->indices[jx].span == 1); + lazy_load_binding (cluster->indices[jx].base, + scope, name, &cluster->slots[jx]); + } + tree bind = cluster->slots[jx]; + if (!bind) + /* Errors could cause there to be nothing. */ + continue; + + if (STAT_HACK_P (bind)) + /* We do not have to check STAT_TYPE here, the xref_tag + machinery deals with that problem. */ + bind = STAT_VISIBLE (bind); + + for (ovl_iterator iter (bind); iter; ++iter) + if (iter.using_p ()) + ; + else if (tree match = duplicate_decls (decl, *iter, hiding)) + { + if (TREE_CODE (match) == TYPE_DECL) + /* The IDENTIFIER will have the type referring to the + now-smashed TYPE_DECL, because ...? Reset it. */ + SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (match)); + + return match; + } + } + + if (TREE_PUBLIC (scope) && TREE_PUBLIC (decl) && !not_module_p () + /* Namespaces are dealt with specially in + make_namespace_finish. */ + && !(TREE_CODE (decl) == NAMESPACE_DECL && !DECL_NAMESPACE_ALIAS (decl))) + { + /* Look in the appropriate mergeable decl slot. */ + tree mergeable = NULL_TREE; + if (named_module_p ()) + mergeable = BINDING_VECTOR_CLUSTER (mvec, BINDING_SLOT_PARTITION + / BINDING_VECTOR_SLOTS_PER_CLUSTER) + .slots[BINDING_SLOT_PARTITION % BINDING_VECTOR_SLOTS_PER_CLUSTER]; + else + mergeable = BINDING_VECTOR_CLUSTER (mvec, 0).slots[BINDING_SLOT_GLOBAL]; + + for (ovl_iterator iter (mergeable); iter; ++iter) + { + tree match = *iter; + + if (duplicate_decls (decl, match, hiding)) + { + if (TREE_CODE (match) == TYPE_DECL) + SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (match)); + return match; + } + } + } + + return NULL_TREE; +} + /* Record DECL as belonging to the current lexical scope. Check for errors (such as an incompatible declaration for the same name already seen in the same scope). IS_FRIEND is true if DECL is @@ -2933,11 +3688,12 @@ do_pushdecl (tree decl, bool hiding) /* An anonymous namespace has a NULL DECL_NAME, but we still want to insert it. Other NULL-named decls, not so much. */ tree name = DECL_NAME (decl); - if (name || TREE_CODE (decl) == NAMESPACE_DECL) + if (name ? !IDENTIFIER_ANON_P (name) : TREE_CODE (decl) == NAMESPACE_DECL) { cxx_binding *binding = NULL; /* Local scope binding. */ tree ns = NULL_TREE; /* Searched namespace. */ tree *slot = NULL; /* Binding slot in namespace. */ + tree *mslot = NULL; /* Current module slot in namespace. */ tree old = NULL_TREE; if (level->kind == sk_namespace) @@ -2951,7 +3707,11 @@ do_pushdecl (tree decl, bool hiding) that's where we'll be pushing anyway. */ slot = find_namespace_slot (ns, name, ns == current_namespace); if (slot) - old = MAYBE_STAT_DECL (*slot); + { + mslot = get_fixed_binding_slot (slot, name, BINDING_SLOT_CURRENT, + ns == current_namespace); + old = MAYBE_STAT_DECL (*mslot); + } } else { @@ -2966,6 +3726,10 @@ do_pushdecl (tree decl, bool hiding) for (ovl_iterator iter (old); iter; ++iter) if (iter.using_p ()) ; /* Ignore using decls here. */ + else if (iter.hidden_p () + && DECL_LANG_SPECIFIC (*iter) + && DECL_MODULE_IMPORT_P (*iter)) + ; /* An undeclared builtin imported from elsewhere. */ else if (tree match = duplicate_decls (decl, *iter, hiding, iter.hidden_p ())) { @@ -3004,6 +3768,26 @@ do_pushdecl (tree decl, bool hiding) return match; } + /* Check for redeclaring an import. */ + if (slot && *slot && TREE_CODE (*slot) == BINDING_VECTOR) + if (tree match + = check_module_override (decl, *slot, hiding, ns, name)) + { + if (match == error_mark_node) + return match; + + /* We found a decl in an interface, push it into this + binding. */ + decl = update_binding (NULL, binding, mslot, old, + match, hiding); + + if (match == decl && DECL_MODULE_EXPORT_P (decl) + && !DECL_MODULE_EXPORT_P (level->this_entity)) + implicitly_export_namespace (level->this_entity); + + return decl; + } + /* We are pushing a new decl. */ /* Skip a hidden builtin we failed to match already. There can @@ -3048,47 +3832,36 @@ do_pushdecl (tree decl, bool hiding) { ns = current_namespace; slot = find_namespace_slot (ns, name, true); + mslot = get_fixed_binding_slot (slot, name, BINDING_SLOT_CURRENT, true); /* Update OLD to reflect the namespace we're going to be pushing into. */ - old = MAYBE_STAT_DECL (*slot); + old = MAYBE_STAT_DECL (*mslot); } - old = update_binding (level, binding, slot, old, decl, hiding); + old = update_binding (level, binding, mslot, old, decl, hiding); if (old != decl) /* An existing decl matched, use it. */ decl = old; - else if (TREE_CODE (decl) == TYPE_DECL) - { - tree type = TREE_TYPE (decl); - - if (type != error_mark_node) - { - if (TYPE_NAME (type) != decl) - set_underlying_type (decl); - - set_identifier_type_value_with_scope (name, decl, level); - } - - /* If this is a locally defined typedef in a function that - is not a template instantation, record it to implement - -Wunused-local-typedefs. */ - if (!instantiating_current_function_p ()) - record_locally_defined_typedef (decl); - } else { - if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) - maybe_register_incomplete_var (decl); + newbinding_bookkeeping (name, decl, level); + + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl) + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + push_local_extern_decl_alias (decl); - if (VAR_OR_FUNCTION_DECL_P (decl)) + if (level->kind == sk_namespace + && TREE_PUBLIC (level->this_entity)) { - if (DECL_LOCAL_DECL_P (decl) - && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) - push_local_extern_decl_alias (decl); + if (TREE_CODE (decl) != CONST_DECL + && DECL_MODULE_EXPORT_P (decl) + && !DECL_MODULE_EXPORT_P (level->this_entity)) + implicitly_export_namespace (level->this_entity); - if (DECL_EXTERN_C_P (decl)) - check_extern_c_conflict (decl); + if (!not_module_p ()) + maybe_record_mergeable_decl (slot, name, decl); } } } @@ -3099,8 +3872,8 @@ do_pushdecl (tree decl, bool hiding) } /* Record a decl-node X as belonging to the current lexical scope. - It's a friend if IS_FRIEND is true -- which affects exactly where - we push it. */ + The new binding is hidden if HIDING is true (an anticipated builtin + or hidden friend). */ tree pushdecl (tree x, bool hiding) @@ -3111,6 +3884,317 @@ pushdecl (tree x, bool hiding) return ret; } +/* A mergeable entity is being loaded into namespace NS slot NAME. + Create and return the appropriate vector slot for that. Either a + GMF slot or a module-specific one. */ + +tree * +mergeable_namespace_slots (tree ns, tree name, bool is_global, tree *vec) +{ + tree *mslot = find_namespace_slot (ns, name, true); + tree *vslot = get_fixed_binding_slot + (mslot, name, is_global ? BINDING_SLOT_GLOBAL : BINDING_SLOT_PARTITION, true); + + gcc_checking_assert (TREE_CODE (*mslot) == BINDING_VECTOR); + *vec = *mslot; + + return vslot; +} + +/* DECL is a new mergeable namespace-scope decl. Add it to the + mergeable entities on GSLOT. */ + +void +add_mergeable_namespace_entity (tree *gslot, tree decl) +{ + *gslot = ovl_make (decl, *gslot); +} + +/* A mergeable entity of KLASS called NAME is being loaded. Return + the set of things it could be. All such non-as_base classes have + been given a member vec. */ + +tree +lookup_class_binding (tree klass, tree name) +{ + tree found = NULL_TREE; + + if (!COMPLETE_TYPE_P (klass)) + ; + else if (TYPE_LANG_SPECIFIC (klass)) + { + vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass); + + found = member_vec_binary_search (member_vec, name); + if (!found) + ; + else if (STAT_HACK_P (found)) + /* Rearrange the stat hack so that we don't need to expose that + internal detail. */ + found = ovl_make (STAT_TYPE (found), STAT_DECL (found)); + else if (IDENTIFIER_CONV_OP_P (name)) + { + gcc_checking_assert (name == conv_op_identifier); + found = OVL_CHAIN (found); + } + } + else + { + gcc_checking_assert (IS_FAKE_BASE_TYPE (klass) + || TYPE_PTRMEMFUNC_P (klass)); + found = fields_linear_search (klass, name, false); + } + + return found; +} + +/* Given a namespace-level binding BINDING, walk it, calling CALLBACK + for all decls of the current module. When partitions are involved, + decls might be mentioned more than once. */ + +unsigned +walk_module_binding (tree binding, bitmap partitions, + bool (*callback) (tree decl, WMB_Flags, void *data), + void *data) +{ + // FIXME: We don't quite deal with using decls naming stat hack + // type. Also using decls exporting something from the same scope. + tree current = binding; + unsigned count = 0; + + if (TREE_CODE (binding) == BINDING_VECTOR) + current = BINDING_VECTOR_CLUSTER (binding, 0).slots[BINDING_SLOT_CURRENT]; + + bool decl_hidden = false; + if (tree type = MAYBE_STAT_TYPE (current)) + { + WMB_Flags flags = WMB_None; + if (STAT_TYPE_HIDDEN_P (current)) + flags = WMB_Flags (flags | WMB_Hidden); + count += callback (type, flags, data); + decl_hidden = STAT_DECL_HIDDEN_P (current); + } + + for (ovl_iterator iter (MAYBE_STAT_DECL (current)); iter; ++iter) + { + if (iter.hidden_p ()) + decl_hidden = true; + if (!(decl_hidden && DECL_IS_UNDECLARED_BUILTIN (*iter))) + { + WMB_Flags flags = WMB_None; + if (decl_hidden) + flags = WMB_Flags (flags | WMB_Hidden); + if (iter.using_p ()) + { + flags = WMB_Flags (flags | WMB_Using); + if (iter.exporting_p ()) + flags = WMB_Flags (flags | WMB_Export); + } + count += callback (*iter, flags, data); + } + decl_hidden = false; + } + + if (partitions && TREE_CODE (binding) == BINDING_VECTOR) + { + /* Process partition slots. */ + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (binding); + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (binding); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + + bool maybe_dups = BINDING_VECTOR_PARTITION_DUPS_P (binding); + + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + if (!cluster->slots[jx].is_lazy ()) + if (tree bind = cluster->slots[jx]) + { + if (TREE_CODE (bind) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (bind)) + { + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (partitions, base)) + goto found; + while (++base, --span); + /* Not a partition's namespace. */ + continue; + found: + + WMB_Flags flags = WMB_None; + if (maybe_dups) + flags = WMB_Flags (flags | WMB_Dups); + count += callback (bind, flags, data); + } + else if (STAT_HACK_P (bind) && MODULE_BINDING_PARTITION_P (bind)) + { + if (tree btype = STAT_TYPE (bind)) + { + WMB_Flags flags = WMB_None; + if (maybe_dups) + flags = WMB_Flags (flags | WMB_Dups); + if (STAT_TYPE_HIDDEN_P (bind)) + flags = WMB_Flags (flags | WMB_Hidden); + + count += callback (btype, flags, data); + } + bool hidden = STAT_DECL_HIDDEN_P (bind); + for (ovl_iterator iter (MAYBE_STAT_DECL (STAT_DECL (bind))); + iter; ++iter) + { + if (iter.hidden_p ()) + hidden = true; + gcc_checking_assert + (!(hidden && DECL_IS_UNDECLARED_BUILTIN (*iter))); + + WMB_Flags flags = WMB_None; + if (maybe_dups) + flags = WMB_Flags (flags | WMB_Dups); + if (decl_hidden) + flags = WMB_Flags (flags | WMB_Hidden); + if (iter.using_p ()) + { + flags = WMB_Flags (flags | WMB_Using); + if (iter.exporting_p ()) + flags = WMB_Flags (flags | WMB_Export); + } + count += callback (*iter, flags, data); + hidden = false; + } + } + } + } + + return count; +} + +/* Imported module MOD has a binding to NS::NAME, stored in section + SNUM. */ + +bool +import_module_binding (tree ns, tree name, unsigned mod, unsigned snum) +{ + tree *slot = find_namespace_slot (ns, name, true); + binding_slot *mslot = append_imported_binding_slot (slot, name, mod); + + if (mslot->is_lazy () || *mslot) + /* Oops, something was already there. */ + return false; + + mslot->set_lazy (snum); + return true; +} + +/* An import of MODULE is binding NS::NAME. There should be no + existing binding for >= MODULE. MOD_GLOB indicates whether MODULE + is a header_unit (-1) or part of the current module (+1). VALUE + and TYPE are the value and type bindings. VISIBLE are the value + bindings being exported. */ + +bool +set_module_binding (tree ns, tree name, unsigned mod, int mod_glob, + tree value, tree type, tree visible) +{ + if (!value) + /* Bogus BMIs could give rise to nothing to bind. */ + return false; + + gcc_assert (TREE_CODE (value) != NAMESPACE_DECL + || DECL_NAMESPACE_ALIAS (value)); + gcc_checking_assert (mod); + + tree *slot = find_namespace_slot (ns, name, true); + binding_slot *mslot = search_imported_binding_slot (slot, mod); + + if (!mslot || !mslot->is_lazy ()) + /* Again, bogus BMI could give find to missing or already loaded slot. */ + return false; + + tree bind = value; + if (type || visible != bind || mod_glob) + { + bind = stat_hack (bind, type); + STAT_VISIBLE (bind) = visible; + if ((mod_glob > 0 && TREE_PUBLIC (ns)) + || (type && DECL_MODULE_EXPORT_P (type))) + STAT_TYPE_VISIBLE_P (bind) = true; + } + + /* Note if this is this-module or global binding. */ + if (mod_glob > 0) + MODULE_BINDING_PARTITION_P (bind) = true; + else if (mod_glob < 0) + MODULE_BINDING_GLOBAL_P (bind) = true; + + *mslot = bind; + + return true; +} + +void +note_pending_specializations (tree ns, tree name, bool is_header) +{ + if (tree *slot = find_namespace_slot (ns, name, false)) + if (TREE_CODE (*slot) == BINDING_VECTOR) + { + tree vec = *slot; + BINDING_VECTOR_PENDING_SPECIALIZATIONS_P (vec) = true; + if (is_header) + BINDING_VECTOR_PENDING_IS_HEADER_P (vec) = true; + else + BINDING_VECTOR_PENDING_IS_PARTITION_P (vec) = true; + } +} + +void +load_pending_specializations (tree ns, tree name) +{ + tree *slot = find_namespace_slot (ns, name, false); + + if (!slot || TREE_CODE (*slot) != BINDING_VECTOR + || !BINDING_VECTOR_PENDING_SPECIALIZATIONS_P (*slot)) + return; + + tree vec = *slot; + BINDING_VECTOR_PENDING_SPECIALIZATIONS_P (vec) = false; + + bool do_header = BINDING_VECTOR_PENDING_IS_HEADER_P (vec); + bool do_partition = BINDING_VECTOR_PENDING_IS_PARTITION_P (vec); + BINDING_VECTOR_PENDING_IS_HEADER_P (vec) = false; + BINDING_VECTOR_PENDING_IS_PARTITION_P (vec) = false; + + gcc_checking_assert (do_header | do_partition); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (vec); + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (vec); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + if (cluster->indices[jx].span + && cluster->slots[jx].is_lazy () + && lazy_specializations_p (cluster->indices[jx].base, + do_header, do_partition)) + lazy_load_binding (cluster->indices[jx].base, ns, name, + &cluster->slots[jx]); +} + +void +add_module_decl (tree ns, tree name, tree decl) +{ + gcc_assert (!DECL_CHAIN (decl)); + add_decl_to_level (NAMESPACE_LEVEL (ns), decl); + newbinding_bookkeeping (name, decl, NAMESPACE_LEVEL (ns)); +} + /* Enter DECL into the symbol table, if that's appropriate. Returns DECL, or a modified version thereof. */ @@ -3717,13 +4801,6 @@ set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b) else { gcc_assert (decl); - 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; @@ -3841,7 +4918,7 @@ pushdecl_outermost_localscope (tree x) static bool do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, - tree *value_p, tree *type_p) + bool insert_p, tree *value_p, tree *type_p) { tree value = *value_p; tree type = *type_p; @@ -3861,13 +4938,33 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, lookup.value = NULL_TREE; } + /* Only process exporting if we're going to be inserting. */ + bool revealing_p = insert_p && !fn_scope_p && module_has_cmi_p (); + + /* First do the value binding. */ if (!lookup.value) - /* Nothing. */; + /* Nothing (only implicit typedef found). */ + gcc_checking_assert (lookup.type); else if (OVL_P (lookup.value) && (!value || OVL_P (value))) { for (lkp_iterator usings (lookup.value); usings; ++usings) { tree new_fn = *usings; + bool exporting = revealing_p && module_exporting_p (); + if (exporting) + { + /* If the using decl is exported, the things it refers + to must also be exported (or not in module purview). */ + if (!DECL_MODULE_EXPORT_P (new_fn) + && (DECL_LANG_SPECIFIC (new_fn) + && DECL_MODULE_PURVIEW_P (new_fn))) + { + error ("%q#D does not have external linkage", new_fn); + inform (DECL_SOURCE_LOCATION (new_fn), + "%q#D declared here", new_fn); + exporting = false; + } + } /* [namespace.udecl] @@ -3875,6 +4972,10 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, scope has the same name and the same parameter types as a function introduced by a using declaration the program is ill-formed. */ + /* This seems overreaching, asking core -- why do we care + about decls in the namespace that we cannot name (because + they are not transitively imported. We just check the + decls that are in this TU. */ bool found = false; for (ovl_iterator old (value); !found && old; ++old) { @@ -3883,8 +4984,25 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, if (new_fn == old_fn) { /* The function already exists in the current - namespace. */ + namespace. We will still want to insert it if + it is revealing a not-revealed thing. */ found = true; + if (!revealing_p) + ; + else if (old.using_p ()) + { + if (exporting) + /* Update in place. 'tis ok. */ + OVL_EXPORT_P (old.get_using ()) = true; + ; + } + else if (DECL_MODULE_EXPORT_P (new_fn)) + ; + else + { + value = old.remove_node (value); + found = false; + } break; } else if (old.using_p ()) @@ -3908,11 +5026,11 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, } } - if (!found) + if (!found && insert_p) /* Unlike the decl-pushing case we don't drop anticipated builtins here. They don't cause a problem, and we'd like to match them with a future declaration. */ - value = ovl_insert (new_fn, value, true); + value = ovl_insert (new_fn, value, 1 + exporting); } } else if (value @@ -3923,28 +5041,34 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, diagnose_name_conflict (lookup.value, value); failed = true; } - else + else if (insert_p) + // FIXME:what if we're newly exporting lookup.value value = lookup.value; - + + /* Now the type binding. */ if (lookup.type && lookup.type != type) { + // FIXME: What if we're exporting lookup.type? if (type && !decls_match (lookup.type, type)) { diagnose_name_conflict (lookup.type, type); failed = true; } - else + else if (insert_p) type = lookup.type; } - /* If value is empty, shift any class or enumeration name back. */ - if (!value) + if (insert_p) { - value = type; - type = NULL_TREE; + /* If value is empty, shift any class or enumeration name back. */ + if (!value) + { + value = type; + type = NULL_TREE; + } + *value_p = value; + *type_p = type; } - *value_p = value; - *type_p = type; return failed; } @@ -4547,7 +5671,8 @@ push_class_level_binding (tree name, tree x) } /* Process and lookup a using decl SCOPE::lookup.name, filling in - lookup.values & lookup.type. Return true if ok. */ + lookup.values & lookup.type. Return a USING_DECL, or NULL_TREE on + failure. */ static tree lookup_using_decl (tree scope, name_lookup &lookup) @@ -4604,6 +5729,16 @@ lookup_using_decl (tree scope, name_lookup &lookup) /* Naming a class member. This is awkward in C++20, because we might be naming an enumerator of an unrelated class. */ + tree npscope = scope; + if (PACK_EXPANSION_P (scope)) + npscope = PACK_EXPANSION_PATTERN (scope); + + if (!MAYBE_CLASS_TYPE_P (npscope)) + { + error ("%qT is not a class, namespace, or enumeration", npscope); + return NULL_TREE; + } + /* You cannot using-decl a destructor. */ if (TREE_CODE (lookup.name) == BIT_NOT_EXPR) { @@ -4612,14 +5747,13 @@ lookup_using_decl (tree scope, name_lookup &lookup) } /* Using T::T declares inheriting ctors, even if T is a typedef. */ - if (MAYBE_CLASS_TYPE_P (scope) - && (lookup.name == TYPE_IDENTIFIER (scope) - || constructor_name_p (lookup.name, scope))) + if (lookup.name == TYPE_IDENTIFIER (npscope) + || constructor_name_p (lookup.name, npscope)) { if (!TYPE_P (current)) { error ("non-member using-declaration names constructor of %qT", - scope); + npscope); return NULL_TREE; } maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); @@ -4627,88 +5761,79 @@ lookup_using_decl (tree scope, name_lookup &lookup) CLASSTYPE_NON_AGGREGATE (current) = true; } - if (!MAYBE_CLASS_TYPE_P (scope)) - ; + if (!TYPE_P (current) && cxx_dialect < cxx20) + { + error ("using-declaration for member at non-class scope"); + return NULL_TREE; + } + + bool depscope = dependent_scope_p (scope); + + if (depscope) + /* Leave binfo null. */; else if (TYPE_P (current)) { - dependent_p = dependent_scope_p (scope); - if (!dependent_p) + binfo = lookup_base (current, scope, ba_any, &b_kind, tf_none); + gcc_checking_assert (b_kind >= bk_not_base); + + if (b_kind == bk_not_base && any_dependent_bases_p ()) + /* Treat as-if dependent. */ + depscope = true; + else if (lookup.name == ctor_identifier + && (b_kind < bk_proper_base || !binfo_direct_p (binfo))) { - binfo = lookup_base (current, scope, ba_any, &b_kind, tf_none); - gcc_checking_assert (b_kind >= bk_not_base); - - if (lookup.name == ctor_identifier) + if (any_dependent_bases_p ()) + depscope = true; + else { - /* Even if there are dependent bases, SCOPE will not - be direct base, no matter. */ - if (b_kind < bk_proper_base || !binfo_direct_p (binfo)) - { - error ("%qT is not a direct base of %qT", scope, current); - return NULL_TREE; - } + error ("%qT is not a direct base of %qT", scope, current); + return NULL_TREE; } - else if (b_kind < bk_proper_base) - binfo = TYPE_BINFO (scope); - else if (IDENTIFIER_CONV_OP_P (lookup.name) - && dependent_type_p (TREE_TYPE (lookup.name))) - dependent_p = true; } + + if (b_kind < bk_proper_base) + binfo = TYPE_BINFO (scope); } else binfo = TYPE_BINFO (scope); + dependent_p = (depscope + || (IDENTIFIER_CONV_OP_P (lookup.name) + && dependent_type_p (TREE_TYPE (lookup.name)))); + if (!dependent_p) - { - if (binfo) - lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2, - /*want_type=*/false, tf_none); + lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2, + /*want_type=*/false, tf_none); - tree saved_value = lookup.value; - if (lookup.value - && b_kind < bk_proper_base) + if (!depscope && b_kind < bk_proper_base) + { + if (cxx_dialect >= cxx20 && lookup.value + && TREE_CODE (lookup.value) == CONST_DECL) { - if (cxx_dialect >= cxx20 - && TREE_CODE (lookup.value) == CONST_DECL) - { - /* Using an unrelated enum; check access here rather - than separately for class and non-class using. */ - perform_or_defer_access_check - (binfo, lookup.value, lookup.value, tf_warning_or_error); - /* And then if this is a copy from handle_using_decl, look - through to the original enumerator. */ - if (CONST_DECL_USING_P (lookup.value)) - lookup.value = DECL_ABSTRACT_ORIGIN (lookup.value); - } - else - lookup.value = NULL_TREE; + /* Using an unrelated enum; check access here rather + than separately for class and non-class using. */ + perform_or_defer_access_check + (binfo, lookup.value, lookup.value, tf_warning_or_error); + /* And then if this is a copy from handle_using_decl, look + through to the original enumerator. */ + if (CONST_DECL_USING_P (lookup.value)) + lookup.value = DECL_ABSTRACT_ORIGIN (lookup.value); } - - if (!lookup.value) + else if (!TYPE_P (current)) { - if (!TYPE_P (current)) - { - error ("using-declaration for member at non-class scope"); - return NULL_TREE; - } - - if (b_kind < bk_proper_base) - { - if (b_kind == bk_not_base && any_dependent_bases_p ()) - /* Treat as-if dependent. */ - dependent_p = true; - else - { - auto_diagnostic_group g; - error_not_base_type (scope, current); - if (saved_value && DECL_IMPLICIT_TYPEDEF_P (saved_value) - && (TREE_CODE (TREE_TYPE (saved_value)) - == ENUMERAL_TYPE)) - inform (input_location, - "did you mean %<using enum %T::%D%>?", - scope, lookup.name); - return NULL_TREE; - } - } + error ("using-declaration for member at non-class scope"); + return NULL_TREE; + } + else + { + auto_diagnostic_group g; + error_not_base_type (scope, current); + if (lookup.value && DECL_IMPLICIT_TYPEDEF_P (lookup.value) + && TREE_CODE (TREE_TYPE (lookup.value)) == ENUMERAL_TYPE) + inform (input_location, + "did you mean %<using enum %T::%D%>?", + scope, lookup.name); + return NULL_TREE; } } } @@ -4757,6 +5882,7 @@ lookup_using_decl (tree scope, name_lookup &lookup) USING_DECL_SCOPE (using_decl) = scope; USING_DECL_DECLS (using_decl) = lookup.value; DECL_DEPENDENT_P (using_decl) = dependent_p; + DECL_CONTEXT (using_decl) = current; if (TYPE_P (current) && b_kind == bk_not_base) USING_DECL_UNRELATED_P (using_decl) = true; @@ -4778,8 +5904,10 @@ do_class_using_decl (tree scope, tree name) } -/* Return the binding for NAME in NS. If NS is NULL, look in - global_namespace. */ +/* Return the binding for NAME in NS in the current TU. If NS is + NULL, look in global_namespace. We will not find declarations + from imports. Users of this who, having found nothing, push a new + decl must be prepared for that pushing to match an existing decl. */ tree get_namespace_binding (tree ns, tree name) @@ -4788,7 +5916,18 @@ get_namespace_binding (tree ns, tree name) if (!ns) ns = global_namespace; gcc_checking_assert (!DECL_NAMESPACE_ALIAS (ns)); - tree ret = find_namespace_value (ns, name); + tree ret = NULL_TREE; + + if (tree *b = find_namespace_slot (ns, name)) + { + ret = *b; + + if (TREE_CODE (ret) == BINDING_VECTOR) + ret = BINDING_VECTOR_CLUSTER (ret, 0).slots[0]; + if (ret) + ret = MAYBE_STAT_DECL (ret); + } + timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } @@ -5089,6 +6228,8 @@ do_namespace_alias (tree alias, tree name_space) DECL_NAMESPACE_ALIAS (alias) = name_space; DECL_EXTERNAL (alias) = 1; DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ()); + set_originating_module (alias); + pushdecl (alias); /* Emit debug info for namespace alias. */ @@ -5143,6 +6284,61 @@ pushdecl_namespace_level (tree x, bool hiding) return t; } +/* Wrapper around push_local_binding to push the bindings for + a non-member USING_DECL with NAME and VALUE. LOOKUP, if non-null, + is the result of name lookup during template parsing. */ + +static void +push_using_decl_bindings (name_lookup *lookup, tree name, tree value) +{ + tree type = NULL_TREE; + + cxx_binding *binding = find_local_binding (current_binding_level, name); + if (binding) + { + value = binding->value; + type = binding->type; + } + + /* DR 36 questions why using-decls at function scope may not be + duplicates. Disallow it, as C++11 claimed and PR 20420 + implemented. */ + if (lookup) + do_nonmember_using_decl (*lookup, true, true, &value, &type); + + if (!value) + ; + else if (binding && value == binding->value) + /* Redeclaration of this USING_DECL. */; + else if (binding && binding->value && TREE_CODE (value) == OVERLOAD) + { + /* We already have this binding, so replace it. */ + update_local_overload (IDENTIFIER_BINDING (name), value); + IDENTIFIER_BINDING (name)->value = value; + } + else + /* Install the new binding. */ + push_local_binding (name, value, /*using=*/true); + + if (!type) + ; + else if (binding && type == binding->type) + ; + else + { + push_local_binding (name, type, /*using=*/true); + set_identifier_type_value (name, type); + } +} + +/* Overload for push_using_decl_bindings that doesn't take a name_lookup. */ + +void +push_using_decl_bindings (tree name, tree value) +{ + push_using_decl_bindings (nullptr, name, value); +} + /* Process a using declaration in non-class scope. */ void @@ -5167,63 +6363,102 @@ finish_nonmember_using_decl (tree scope, tree name) if (current_binding_level->kind == sk_namespace) { tree *slot = find_namespace_slot (current_namespace, name, true); + tree *mslot = get_fixed_binding_slot (slot, name, + BINDING_SLOT_CURRENT, true); + bool failed = false; - tree value = MAYBE_STAT_DECL (*slot); - tree type = MAYBE_STAT_TYPE (*slot); + if (mslot != slot) + { + /* A module vector. I presume the binding list is going to + be sparser than the import bitmap. Hence iterate over + the former checking for bits set in the bitmap. */ + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (*slot); + + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (*slot); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } - do_nonmember_using_decl (lookup, false, &value, &type); + /* Do this in forward order, so we load modules in an order + the user expects. */ + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Are we importing this module? */ + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (imports, base)) + goto found; + while (++base, --span); + continue; - if (STAT_HACK_P (*slot)) - { - STAT_DECL (*slot) = value; - STAT_TYPE (*slot) = type; - } - else if (type) - *slot = stat_hack (value, type); - else - *slot = value; - } - else - { - add_decl_expr (using_decl); + found:; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + { + gcc_assert (cluster->indices[jx].span == 1); + lazy_load_binding (cluster->indices[jx].base, + scope, name, &cluster->slots[jx]); + } - cxx_binding *binding = find_local_binding (current_binding_level, name); - tree value = NULL; - tree type = NULL; - if (binding) - { - value = binding->value; - type = binding->type; - } + tree value = cluster->slots[jx]; + if (!value) + /* Load errors could mean there's nothing here. */ + continue; - /* DR 36 questions why using-decls at function scope may not be - duplicates. Disallow it, as C++11 claimed and PR 20420 - implemented. */ - do_nonmember_using_decl (lookup, true, &value, &type); + /* Extract what we can see from here. If there's no + stat_hack, then everything was exported. */ + tree type = NULL_TREE; - if (!value) - ; - else if (binding && value == binding->value) - ; - else if (binding && binding->value && TREE_CODE (value) == OVERLOAD) - { - update_local_overload (IDENTIFIER_BINDING (name), value); - IDENTIFIER_BINDING (name)->value = value; + /* If no stat hack, everything is visible. */ + if (STAT_HACK_P (value)) + { + if (STAT_TYPE_VISIBLE_P (value)) + type = STAT_TYPE (value); + value = STAT_VISIBLE (value); + } + + if (do_nonmember_using_decl (lookup, false, false, + &value, &type)) + { + failed = true; + break; + } + } } - else - /* Install the new binding. */ - push_local_binding (name, value, true); - if (!type) - ; - else if (binding && type == binding->type) - ; - else + if (!failed) { - push_local_binding (name, type, true); - set_identifier_type_value (name, type); + /* Now do the current slot. */ + tree value = MAYBE_STAT_DECL (*mslot); + tree type = MAYBE_STAT_TYPE (*mslot); + + do_nonmember_using_decl (lookup, false, true, &value, &type); + + // FIXME: Partition mergeableness? + if (STAT_HACK_P (*mslot)) + { + STAT_DECL (*mslot) = value; + STAT_TYPE (*mslot) = type; + } + else if (type) + *mslot = stat_hack (value, type); + else + *mslot = value; } } + else + { + add_decl_expr (using_decl); + if (DECL_DEPENDENT_P (using_decl)) + lookup.value = using_decl; + push_using_decl_bindings (&lookup, name, NULL_TREE); + } } /* Return the declarations that are members of the namespace NS. */ @@ -5851,7 +7086,7 @@ get_std_name_hint (const char *name) /* Describe DIALECT. */ -static const char * +const char * get_cxx_dialect_name (enum cxx_dialect dialect) { switch (dialect) @@ -6122,9 +7357,10 @@ maybe_add_fuzzy_decl (auto_vec<tree> &vec, tree decl) } /* Examing the namespace binding BINDING, and add at most one instance - of the name, if it contains a visible entity of interest. */ + of the name, if it contains a visible entity of interest. Return + true if we added something. */ -void +bool maybe_add_fuzzy_binding (auto_vec<tree> &vec, tree binding, lookup_name_fuzzy_kind kind) { @@ -6136,7 +7372,7 @@ maybe_add_fuzzy_binding (auto_vec<tree> &vec, tree binding, && STAT_TYPE (binding)) { if (maybe_add_fuzzy_decl (vec, STAT_TYPE (binding))) - return; + return true; } else if (!STAT_DECL_HIDDEN_P (binding)) value = STAT_DECL (binding); @@ -6151,8 +7387,11 @@ maybe_add_fuzzy_binding (auto_vec<tree> &vec, tree binding, if (kind != FUZZY_LOOKUP_TYPENAME || TREE_CODE (STRIP_TEMPLATE (value)) == TYPE_DECL) if (maybe_add_fuzzy_decl (vec, value)) - return; + return true; } + + /* Nothing found. */ + return false; } /* Helper function for lookup_name_fuzzy. @@ -6218,8 +7457,54 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm, (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); + { + tree binding = *iter; + + if (TREE_CODE (binding) == BINDING_VECTOR) + { + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (binding); + + if (tree bind = cluster->slots[BINDING_SLOT_CURRENT]) + if (maybe_add_fuzzy_binding (vec, bind, kind)) + continue; + + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (binding); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; + jx++) + { + /* Are we importing this module? */ + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (imports, base)) + goto found; + while (++base, --span); + continue; + + found:; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + /* Let's not read in everything on the first + spello! **/ + continue; + if (tree bind = cluster->slots[jx]) + if (maybe_add_fuzzy_binding (vec, bind, kind)) + break; + } + } + else + maybe_add_fuzzy_binding (vec, binding, kind); + } + vec.qsort ([] (const void *a_, const void *b_) { return strcmp (IDENTIFIER_POINTER (*(const tree *)a_), @@ -6762,31 +8047,115 @@ lookup_elaborated_type_1 (tree name, TAG_how how) tree ns = b->this_entity; if (tree *slot = find_namespace_slot (ns, name)) { - /* If this is the kind of thing we're looking for, we're done. */ - if (tree type = MAYBE_STAT_TYPE (*slot)) - { - if (how != TAG_how::HIDDEN_FRIEND) - /* No longer hidden. */ - STAT_TYPE_HIDDEN_P (*slot) = false; + tree bind = *slot; + if (TREE_CODE (bind) == BINDING_VECTOR) + bind = BINDING_VECTOR_CLUSTER (bind, 0).slots[BINDING_SLOT_CURRENT]; - return type; - } - else if (tree decl = MAYBE_STAT_DECL (*slot)) + if (bind) { - if (qualify_lookup (decl, LOOK_want::TYPE)) + /* If this is the kind of thing we're looking for, we're done. */ + if (tree type = MAYBE_STAT_TYPE (bind)) { - if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (*slot) - && STAT_DECL_HIDDEN_P (*slot)) + if (how != TAG_how::HIDDEN_FRIEND) + /* No longer hidden. */ + STAT_TYPE_HIDDEN_P (*slot) = false; + + return type; + } + else if (tree decl = MAYBE_STAT_DECL (bind)) + { + if (qualify_lookup (decl, LOOK_want::TYPE)) { - if (STAT_TYPE (*slot)) - STAT_DECL_HIDDEN_P (*slot) = false; - else - /* There is no type, just remove the stat - hack. */ - *slot = decl; + if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (bind) + && STAT_DECL_HIDDEN_P (bind)) + { + if (STAT_TYPE (bind)) + STAT_DECL_HIDDEN_P (bind) = false; + else + { + /* There is no type, just remove the stat + hack. */ + if (*slot == bind) + *slot = decl; + else + BINDING_VECTOR_CLUSTER (bind, 0) + .slots[BINDING_SLOT_CURRENT] = decl; + } + } + return decl; } + } + } - return decl; + if (TREE_CODE (*slot) == BINDING_VECTOR) + { + /* We could be redeclaring a global module entity, (from GMF + or header unit), or from another partition, or + specializing an imported template. */ + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (*slot); + + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (*slot); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } + + /* Do this in forward order, so we load modules in an order + the user expects. */ + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Are we importing this module? */ + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (imports, base)) + goto found; + while (++base, --span); + continue; + + found:; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + { + gcc_assert (cluster->indices[jx].span == 1); + lazy_load_binding (cluster->indices[jx].base, + ns, name, &cluster->slots[jx]); + } + tree bind = cluster->slots[jx]; + if (!bind) + /* Load errors could mean there's nothing here. */ + continue; + + /* Extract what we can see from here. If there's no + stat_hack, then everything was exported. */ + tree type = NULL_TREE; + + /* If no stat hack, everything is visible. */ + if (STAT_HACK_P (bind)) + { + if (STAT_TYPE_VISIBLE_P (bind)) + type = STAT_TYPE (bind); + bind = STAT_VISIBLE (bind); + } + + if (type && qualify_lookup (type, LOOK_want::TYPE)) + return type; + + if (bind && qualify_lookup (bind, LOOK_want::TYPE)) + return bind; + } + + if (!module_purview_p ()) + { + /* We're in the global module, perhaps there's a tag + there? */ + // FIXME: This isn't quite right, if we find something + // here, from the language PoV we're not supposed to + // know it? } } } @@ -6918,7 +8287,6 @@ do_pushtag (tree name, tree type, TAG_how how) if (identifier_type_value_1 (name) != type) { tree tdef; - int in_class = 0; tree context = TYPE_CONTEXT (type); if (! context) @@ -6949,20 +8317,19 @@ do_pushtag (tree name, tree type, TAG_how how) if (!context) context = current_namespace; - if (b->kind == sk_class - || (b->kind == sk_template_parms - && b->level_chain->kind == sk_class)) - in_class = 1; - tdef = create_implicit_typedef (name, type); DECL_CONTEXT (tdef) = FROB_CONTEXT (context); + set_originating_module (tdef); + decl = maybe_process_template_type_declaration (type, how == TAG_how::HIDDEN_FRIEND, b); if (decl == error_mark_node) return decl; + bool in_class = false; if (b->kind == sk_class) { + in_class = true; if (!TYPE_BEING_DEFINED (current_class_type)) /* Don't push anywhere if the class is complete; a lambda in an NSDMI is not a member of the class. */ @@ -6976,7 +8343,9 @@ do_pushtag (tree name, tree type, TAG_how how) else pushdecl_class_level (decl); } - else if (b->kind != sk_template_parms) + else if (b->kind == sk_template_parms) + in_class = b->level_chain->kind == sk_class; + else { decl = do_pushdecl_with_scope (decl, b, /*hiding=*/(how == TAG_how::HIDDEN_FRIEND)); @@ -6993,7 +8362,7 @@ do_pushtag (tree name, tree type, TAG_how how) } } - if (! in_class) + if (!in_class) set_identifier_type_value_with_scope (name, tdef, b); TYPE_CONTEXT (type) = DECL_CONTEXT (decl); @@ -7280,8 +8649,6 @@ do_push_nested_namespace (tree ns) else { do_push_nested_namespace (CP_DECL_CONTEXT (ns)); - gcc_checking_assert - (find_namespace_value (current_namespace, DECL_NAME (ns)) == ns); resume_scope (NAMESPACE_LEVEL (ns)); current_namespace = ns; } @@ -7303,10 +8670,10 @@ do_pop_nested_namespace (tree ns) do_pop_from_top_level (); } -/* Add TARGET to USINGS, if it does not already exist there. - We used to build the complete graph of usings at this point, from - the POV of the source namespaces. Now we build that as we perform - the unqualified search. */ +/* Add TARGET to USINGS, if it does not already exist there. We used + to build the complete graph of usings at this point, from the POV + of the source namespaces. Now we build that as we perform the + unqualified search. */ static void add_using_namespace (vec<tree, va_gc> *&usings, tree target) @@ -7413,6 +8780,87 @@ push_inline_namespaces (tree ns) return count; } +/* SLOT is the (possibly empty) binding slot for NAME in CTX. + Reuse or create a namespace NAME. NAME is null for the anonymous + namespace. */ + +static tree +reuse_namespace (tree *slot, tree ctx, tree name) +{ + if (modules_p () && *slot && TREE_PUBLIC (ctx) && name) + { + /* Public namespace. Shared. */ + tree *global_slot = slot; + if (TREE_CODE (*slot) == BINDING_VECTOR) + global_slot = get_fixed_binding_slot (slot, name, + BINDING_SLOT_GLOBAL, false); + + for (ovl_iterator iter (*global_slot); iter; ++iter) + { + tree decl = *iter; + + if (TREE_CODE (decl) == NAMESPACE_DECL && !DECL_NAMESPACE_ALIAS (decl)) + return decl; + } + } + return NULL_TREE; +} + +static tree +make_namespace (tree ctx, tree name, location_t loc, bool inline_p) +{ + /* Create the namespace. */ + tree ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); + DECL_SOURCE_LOCATION (ns) = loc; + SCOPE_DEPTH (ns) = SCOPE_DEPTH (ctx) + 1; + if (!SCOPE_DEPTH (ns)) + /* We only allow depth 255. */ + sorry ("cannot nest more than %d namespaces", SCOPE_DEPTH (ctx)); + DECL_CONTEXT (ns) = FROB_CONTEXT (ctx); + + if (!name) + /* Anon-namespaces in different header-unit imports are distinct. + But that's ok as their contents all have internal linkage. + (This is different to how they'd behave as textual includes, + but doing this at all is really odd source.) */ + SET_DECL_ASSEMBLER_NAME (ns, anon_identifier); + else if (TREE_PUBLIC (ctx)) + TREE_PUBLIC (ns) = true; + + if (inline_p) + DECL_NAMESPACE_INLINE_P (ns) = true; + + return ns; +} + +/* NS was newly created, finish off making it. */ + +static void +make_namespace_finish (tree ns, tree *slot, bool from_import = false) +{ + if (modules_p () && TREE_PUBLIC (ns) && (from_import || *slot != ns)) + { + /* Merge into global slot. */ + tree *gslot = get_fixed_binding_slot (slot, DECL_NAME (ns), + BINDING_SLOT_GLOBAL, true); + *gslot = ns; + } + + tree ctx = CP_DECL_CONTEXT (ns); + cp_binding_level *scope = ggc_cleared_alloc<cp_binding_level> (); + scope->this_entity = ns; + scope->more_cleanups_ok = true; + scope->kind = sk_namespace; + scope->level_chain = NAMESPACE_LEVEL (ctx); + NAMESPACE_LEVEL (ns) = scope; + + if (DECL_NAMESPACE_INLINE_P (ns)) + vec_safe_push (DECL_NAMESPACE_INLINEES (ctx), ns); + + if (DECL_NAMESPACE_INLINE_P (ns) || !DECL_NAME (ns)) + emit_debug_info_using_namespace (ctx, ns, true); +} + /* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we enter an anonymous namespace. If MAKE_INLINE is true, then we create an inline namespace (it is up to the caller to check upon @@ -7489,59 +8937,80 @@ push_namespace (tree name, bool make_inline) } } - bool new_ns = false; if (ns) - /* DR2061. NS might be a member of an inline namespace. We - need to push into those namespaces. */ - count += push_inline_namespaces (CP_DECL_CONTEXT (ns)); + { + /* DR2061. NS might be a member of an inline namespace. We + need to push into those namespaces. */ + if (modules_p ()) + { + for (tree parent, ctx = ns; ctx != current_namespace; + ctx = parent) + { + parent = CP_DECL_CONTEXT (ctx); + + tree bind = *find_namespace_slot (parent, DECL_NAME (ctx), false); + if (bind != ctx) + { + auto &cluster = BINDING_VECTOR_CLUSTER (bind, 0); + binding_slot &slot = cluster.slots[BINDING_SLOT_CURRENT]; + gcc_checking_assert (!(tree)slot || (tree)slot == ctx); + slot = ctx; + } + } + } + + count += push_inline_namespaces (CP_DECL_CONTEXT (ns)); + if (DECL_SOURCE_LOCATION (ns) == BUILTINS_LOCATION) + /* It's not builtin now. */ + DECL_SOURCE_LOCATION (ns) = input_location; + } else { - ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); - SCOPE_DEPTH (ns) = SCOPE_DEPTH (current_namespace) + 1; - if (!SCOPE_DEPTH (ns)) - /* We only allow depth 255. */ - sorry ("cannot nest more than %d namespaces", - SCOPE_DEPTH (current_namespace)); - DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace); - new_ns = true; + /* Before making a new namespace, see if we already have one in + the existing partitions of the current namespace. */ + tree *slot = find_namespace_slot (current_namespace, name, false); + if (slot) + ns = reuse_namespace (slot, current_namespace, name); + if (!ns) + ns = make_namespace (current_namespace, name, + input_location, make_inline); if (pushdecl (ns) == error_mark_node) ns = NULL_TREE; else { - if (!name) - { - SET_DECL_ASSEMBLER_NAME (ns, anon_identifier); - - if (!make_inline) - add_using_namespace (current_binding_level->using_directives, - ns); - } - else if (TREE_PUBLIC (current_namespace)) - TREE_PUBLIC (ns) = 1; - - if (make_inline) + /* Finish up making the namespace. */ + add_decl_to_level (NAMESPACE_LEVEL (current_namespace), ns); + if (!slot) { - DECL_NAMESPACE_INLINE_P (ns) = true; - vec_safe_push (DECL_NAMESPACE_INLINEES (current_namespace), ns); + slot = find_namespace_slot (current_namespace, name); + /* This should find the slot created by pushdecl. */ + gcc_checking_assert (slot && *slot == ns); } + make_namespace_finish (ns, slot); - if (!name || make_inline) - emit_debug_info_using_namespace (current_namespace, ns, true); + /* Add the anon using-directive here, we don't do it in + make_namespace_finish. */ + if (!DECL_NAMESPACE_INLINE_P (ns) && !name) + add_using_namespace (current_binding_level->using_directives, ns); } } if (ns) { + /* A public namespace is exported only if explicitly marked, or + it contains exported entities. */ + if (!DECL_MODULE_EXPORT_P (ns) && TREE_PUBLIC (ns) + && module_exporting_p ()) + implicitly_export_namespace (ns); + if (make_inline && !DECL_NAMESPACE_INLINE_P (ns)) { - error ("inline namespace must be specified at initial definition"); + error_at (input_location, + "inline namespace must be specified at initial definition"); inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns); } - if (new_ns) - begin_scope (sk_namespace, ns); - else - resume_scope (NAMESPACE_LEVEL (ns)); + resume_scope (NAMESPACE_LEVEL (ns)); current_namespace = ns; count++; } @@ -7565,6 +9034,69 @@ pop_namespace (void) timevar_cond_stop (TV_NAME_LOOKUP, subtime); } +/* An import is defining namespace NAME inside CTX. Find or create + that namespace and add it to the container's binding-vector. */ + +tree +add_imported_namespace (tree ctx, tree name, unsigned origin, location_t loc, + bool visible_p, bool inline_p) +{ + // FIXME: Something is not correct about the VISIBLE_P handling. We + // need to insert this namespace into + // (a) the GLOBAL or PARTITION slot, if it is TREE_PUBLIC + // (b) The importing module's slot (always) + // (c) Do we need to put it in the CURRENT slot? This is the + // confused piece. + + gcc_checking_assert (origin); + tree *slot = find_namespace_slot (ctx, name, true); + tree decl = reuse_namespace (slot, ctx, name); + if (!decl) + { + decl = make_namespace (ctx, name, loc, inline_p); + DECL_MODULE_IMPORT_P (decl) = true; + make_namespace_finish (decl, slot, true); + } + else if (DECL_NAMESPACE_INLINE_P (decl) != inline_p) + { + error_at (loc, "%s namespace %qD conflicts with reachable definition", + inline_p ? "inline" : "non-inline", decl); + inform (DECL_SOURCE_LOCATION (decl), "reachable %s definition here", + inline_p ? "non-inline" : "inline"); + } + + if (TREE_PUBLIC (decl) && TREE_CODE (*slot) == BINDING_VECTOR) + { + /* See if we can extend the final slot. */ + binding_cluster *last = BINDING_VECTOR_CLUSTER_LAST (*slot); + gcc_checking_assert (last->indices[0].span); + unsigned jx = BINDING_VECTOR_SLOTS_PER_CLUSTER; + + while (--jx) + if (last->indices[jx].span) + break; + tree final = last->slots[jx]; + if (visible_p == !STAT_HACK_P (final) + && MAYBE_STAT_DECL (final) == decl + && last->indices[jx].base + last->indices[jx].span == origin + && (BINDING_VECTOR_NUM_CLUSTERS (*slot) > 1 + || (BINDING_VECTOR_SLOTS_PER_CLUSTER > BINDING_SLOTS_FIXED + && jx >= BINDING_SLOTS_FIXED))) + { + last->indices[jx].span++; + return decl; + } + } + + /* Append a new slot. */ + tree *mslot = &(tree &)*append_imported_binding_slot (slot, name, origin); + + gcc_assert (!*mslot); + *mslot = visible_p ? decl : stat_hack (decl, NULL_TREE); + + return decl; +} + /* External entry points for do_{push_to/pop_from}_top_level. */ void @@ -7720,8 +9252,8 @@ maybe_save_operator_binding (tree e) /* 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; + if (!module_has_cmi_p () && !global_purview_p () && !current_lambda_expr()) + return; tree fnname = ovl_op_identifier (false, TREE_CODE (e)); if (!fnname) diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 9cc8a42..75db5b3 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -1,5 +1,5 @@ /* Declarations for -*- C++ -*- name lookup routines. - Copyright (C) 2003-2020 Free Software Foundation, Inc. + Copyright (C) 2003-2021 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> This file is part of GCC. @@ -457,7 +457,7 @@ extern tree *find_member_slot (tree klass, tree name); extern tree *add_member_slot (tree klass, tree name); extern void resort_type_member_vec (void *, void *, gt_pointer_operator, void *); -extern void set_class_bindings (tree, unsigned extra = 0); +extern vec<tree, va_gc> *set_class_bindings (tree, int extra = 0); extern void insert_late_enum_def_bindings (tree, tree); extern tree innermost_non_namespace_value (tree); extern cxx_binding *outer_binding (tree, cxx_binding *, bool); @@ -478,6 +478,37 @@ extern void push_to_top_level (void); extern void pop_from_top_level (void); extern void maybe_save_operator_binding (tree); extern void push_operator_bindings (void); +extern void push_using_decl_bindings (tree, tree); extern void discard_operator_bindings (tree); +/* Lower level interface for modules. */ +extern tree *mergeable_namespace_slots (tree ns, tree name, bool is_global, + tree *mvec); +extern void add_mergeable_namespace_entity (tree *slot, tree decl); +extern tree lookup_class_binding (tree ctx, tree name); +extern bool import_module_binding (tree ctx, tree name, unsigned mod, + unsigned snum); +extern bool set_module_binding (tree ctx, tree name, unsigned mod, + int mod_glob_flag, + tree value, tree type, tree visible); +extern void add_module_decl (tree ctx, tree name, tree decl); + +enum WMB_Flags +{ + WMB_None = 0, + WMB_Dups = 1 << 0, + WMB_Export = 1 << 1, + WMB_Using = 1 << 2, + WMB_Hidden = 1 << 3, +}; + +extern unsigned walk_module_binding (tree binding, bitmap partitions, + bool (*)(tree decl, WMB_Flags, void *data), + void *data); +extern tree add_imported_namespace (tree ctx, tree name, unsigned module, + location_t, bool visible_p, bool inline_p); +extern void note_pending_specializations (tree ns, tree name, bool is_header); +extern void load_pending_specializations (tree ns, tree name); +extern const char *get_cxx_dialect_name (enum cxx_dialect dialect); + #endif /* GCC_CP_NAME_LOOKUP_H */ diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def index d239535..3e9066d 100644 --- a/gcc/cp/operators.def +++ b/gcc/cp/operators.def @@ -5,7 +5,7 @@ non-overloadable operators (like the `?:' ternary operator). Written by Mark Mitchell <mark@codesourcery.com> - Copyright (C) 2000-2020 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 127d7fa..22ed7d3 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -1,5 +1,5 @@ /* Perform optimizations on tree structure. - Copyright (C) 1998-2020 Free Software Foundation, Inc. + Copyright (C) 1998-2021 Free Software Foundation, Inc. Written by Mark Michell (mark@codesourcery.com). This file is part of GCC. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index cc3da15..abadaf9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1,5 +1,5 @@ /* -*- C++ -*- Parser. - Copyright (C) 2000-2020 Free Software Foundation, Inc. + Copyright (C) 2000-2021 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com>. This file is part of GCC. @@ -646,9 +646,17 @@ cp_lexer_new_main (void) /* Put the first token in the buffer. */ cp_token *tok = lexer->buffer->quick_push (token); + uintptr_t filter = 0; + if (modules_p ()) + filter = module_token_cdtor (parse_in, filter); + /* Get the remaining tokens from the preprocessor. */ while (tok->type != CPP_EOF) { + if (filter) + /* Process the previous token. */ + module_token_lang (tok->type, tok->keyword, tok->u.value, + tok->location, filter); tok = vec_safe_push (lexer->buffer, cp_token ()); cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok); } @@ -658,10 +666,25 @@ cp_lexer_new_main (void) + lexer->buffer->length () - 1; + if (lexer->buffer->length () != 1) + { + /* Set the EOF token's location to be the just after the previous + token's range. That way 'at-eof' diagnostics point at something + meaninful. */ + auto range = get_range_from_loc (line_table, tok[-1].location); + tok[0].location + = linemap_position_for_loc_and_offset (line_table, range.m_finish, 1); + } + + if (filter) + module_token_cdtor (parse_in, filter); + /* Subsequent preprocessor diagnostics should use compiler diagnostic functions to get the compiler source location. */ done_lexing = true; + maybe_check_all_macros (parse_in); + gcc_assert (!lexer->next_token->purged_p); return lexer; } @@ -842,6 +865,8 @@ cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token) token->purged_p = false; token->error_reported = false; token->tree_check_p = false; + /* Usually never see a zero, but just in case ... */ + token->main_source_p = line_table->depth <= 1; /* On some systems, some header files are surrounded by an implicit extern "C" block. Set a flag in the token if it @@ -2190,6 +2215,28 @@ static tree cp_parser_implicitly_scoped_statement static void cp_parser_already_scoped_statement (cp_parser *, bool *, const token_indent_info &); +/* State of module-declaration parsing. */ +enum module_parse +{ + MP_NOT_MODULE, /* Not a module. */ + + _MP_UNUSED, + + MP_FIRST, /* First declaration of TU. */ + MP_GLOBAL, /* Global Module Fragment. */ + + MP_PURVIEW_IMPORTS, /* Imports of a module. */ + MP_PURVIEW, /* Purview of a named module. */ + + MP_PRIVATE_IMPORTS, /* Imports of a Private Module Fragment. */ + MP_PRIVATE, /* Private Module Fragment. */ +}; + +static module_parse cp_parser_module_declaration + (cp_parser *parser, module_parse, bool exporting); +static void cp_parser_import_declaration + (cp_parser *parser, module_parse, bool exporting); + /* Declarations [gram.dcl.dcl] */ static void cp_parser_declaration_seq_opt @@ -3419,6 +3466,15 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id, else if (cxx_dialect < cxx11 && id == ridpointers[(int)RID_NOEXCEPT]) inform (location, "C++11 %<noexcept%> only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); + else if (TREE_CODE (id) == IDENTIFIER_NODE + && (id_equal (id, "module") || id_equal (id, "import"))) + { + if (!modules_p ()) + inform (location, "%qE only available with %<-fmodules-ts%>", id); + else + inform (location, "%qE was not recognized as a module control-line", + id); + } else if (cxx_dialect < cxx11 && TREE_CODE (id) == IDENTIFIER_NODE && id_equal (id, "thread_local")) @@ -3712,6 +3768,13 @@ cp_parser_skip_to_closing_parenthesis_1 (cp_parser *parser, condop_depth--; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* We fell into a pragma. Skip it, and continue. */ cp_parser_skip_to_pragma_eol (parser, recovering ? token : nullptr); @@ -3808,6 +3871,13 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) ++nesting_depth; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* We fell into a pragma. Skip it, and continue or return. */ cp_parser_skip_to_pragma_eol (parser, token); @@ -3890,6 +3960,13 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser) nesting_depth++; break; + case CPP_KEYWORD: + if (token->keyword != RID__EXPORT + && token->keyword != RID__MODULE + && token->keyword != RID__IMPORT) + break; + /* FALLTHROUGH */ + case CPP_PRAGMA: /* Skip it, and continue or return. */ cp_parser_skip_to_pragma_eol (parser, token); @@ -4771,6 +4848,10 @@ cp_parser_translation_unit (cp_parser* parser) push_deferring_access_checks (flag_access_control ? dk_no_deferred : dk_no_check); + module_parse mp_state = MP_NOT_MODULE; + if (modules_p () && !header_module_p ()) + mp_state = MP_FIRST; + bool implicit_extern_c = false; /* Parse until EOF. */ @@ -4794,6 +4875,55 @@ cp_parser_translation_unit (cp_parser* parser) if (token->type == CPP_EOF) break; + if (modules_p ()) + { + /* Top-level module declarations are ok, and change the + portion of file we're in. Top-level import declarations + are significant for the import portions. */ + + cp_token *next = token; + bool exporting = token->keyword == RID__EXPORT; + if (exporting) + { + cp_lexer_consume_token (parser->lexer); + next = cp_lexer_peek_token (parser->lexer); + } + if (next->keyword == RID__MODULE) + { + mp_state + = cp_parser_module_declaration (parser, mp_state, exporting); + continue; + } + else if (next->keyword == RID__IMPORT) + { + if (mp_state == MP_FIRST) + mp_state = MP_NOT_MODULE; + cp_parser_import_declaration (parser, mp_state, exporting); + continue; + } + else + gcc_checking_assert (!exporting); + + if (mp_state == MP_GLOBAL && token->main_source_p) + { + static bool warned = false; + if (!warned) + { + warned = true; + error_at (token->location, + "global module fragment contents must be" + " from preprocessor inclusion"); + } + } + } + + /* This relies on the ordering of module_parse values. */ + if (mp_state == MP_PURVIEW_IMPORTS || mp_state == MP_PRIVATE_IMPORTS) + /* We're no longer in the import portion of a named module. */ + mp_state = module_parse (mp_state + 1); + else if (mp_state == MP_FIRST) + mp_state = MP_NOT_MODULE; + if (token->type == CPP_CLOSE_BRACE) { cp_parser_error (parser, "expected declaration"); @@ -8804,7 +8934,7 @@ cp_parser_has_attribute_expression (cp_parser *parser) { if (oper == error_mark_node) /* Nothing. */; - else if (type_dependent_expression_p (oper)) + else if (processing_template_decl && uses_template_parms (oper)) sorry_at (atloc, "%<__builtin_has_attribute%> with dependent argument " "not supported yet"); else @@ -13513,9 +13643,239 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p, } } +/* Modules */ + +/* Parse a module-name, + identifier + module-name . identifier + header-name + + Returns a pointer to module object, NULL. */ + +static module_state * +cp_parser_module_name (cp_parser *parser) +{ + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_HEADER_NAME) + { + cp_lexer_consume_token (parser->lexer); + + return get_module (token->u.value); + } + + module_state *parent = NULL; + bool partitioned = false; + if (token->type == CPP_COLON && named_module_p ()) + { + partitioned = true; + cp_lexer_consume_token (parser->lexer); + } + + for (;;) + { + if (cp_lexer_peek_token (parser->lexer)->type != CPP_NAME) + { + cp_parser_error (parser, "expected module-name"); + break; + } + + tree name = cp_lexer_consume_token (parser->lexer)->u.value; + parent = get_module (name, parent, partitioned); + token = cp_lexer_peek_token (parser->lexer); + if (!partitioned && token->type == CPP_COLON) + partitioned = true; + else if (token->type != CPP_DOT) + break; + + cp_lexer_consume_token (parser->lexer); + } + + return parent; +} + +/* Named module-declaration + __module ; PRAGMA_EOL + __module private ; PRAGMA_EOL (unimplemented) + [__export] __module module-name attr-spec-seq-opt ; PRAGMA_EOL +*/ + +static module_parse +cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, + bool exporting) +{ + /* We're a pseudo pragma. */ + parser->lexer->in_pragma = true; + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (mp_state == MP_FIRST && !exporting + && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Start global module fragment. */ + cp_lexer_consume_token (parser->lexer); + module_kind |= MK_GLOBAL; + mp_state = MP_GLOBAL; + cp_parser_require_pragma_eol (parser, token); + } + else if (!exporting + && cp_lexer_next_token_is (parser->lexer, CPP_COLON) + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_PRIVATE) + && cp_lexer_nth_token_is (parser->lexer, 3, CPP_SEMICOLON)) + { + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_parser_require_pragma_eol (parser, token); + + if (!(mp_state == MP_PURVIEW || mp_state == MP_PURVIEW_IMPORTS) + || !module_interface_p () || module_partition_p ()) + error_at (token->location, + "private module fragment only permitted in purview" + " of module interface or partition"); + else + { + mp_state = MP_PRIVATE_IMPORTS; + sorry_at (token->location, "private module fragment"); + } + } + else if (!(mp_state == MP_FIRST || mp_state == MP_GLOBAL)) + { + /* Neither the first declaration, nor in a GMF. */ + error_at (token->location, "module-declaration only permitted as first" + " declaration, or ending a global module fragment"); + skip_eol: + cp_parser_skip_to_pragma_eol (parser, token); + } + else + { + module_state *mod = cp_parser_module_name (parser); + tree attrs = cp_parser_attributes_opt (parser); + + mp_state = MP_PURVIEW_IMPORTS; + if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto skip_eol; + + declare_module (mod, token->location, exporting, attrs, parse_in); + cp_parser_require_pragma_eol (parser, token); + } + + return mp_state; +} + +/* Import-declaration + [__export] __import module-name attr-spec-seq-opt ; PRAGMA_EOL */ + +static void +cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, + bool exporting) +{ + /* We're a pseudo pragma. */ + parser->lexer->in_pragma = true; + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (mp_state != MP_PURVIEW_IMPORTS + && mp_state != MP_PRIVATE_IMPORTS + && module_purview_p () + && !global_purview_p ()) + { + error_at (token->location, "post-module-declaration" + " imports must be contiguous"); + note_lexer: + inform (token->location, "perhaps insert a line break, or other" + " disambiguation, to prevent this being considered a" + " module control-line"); + skip_eol: + cp_parser_skip_to_pragma_eol (parser, token); + } + else if (current_scope () != global_namespace) + { + error_at (token->location, "import-declaration must be at global scope"); + goto note_lexer; + } + else + { + module_state *mod = cp_parser_module_name (parser); + tree attrs = cp_parser_attributes_opt (parser); + + if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) + goto skip_eol; + cp_parser_require_pragma_eol (parser, token); + + if (parser->in_unbraced_linkage_specification_p) + error_at (token->location, "import cannot appear directly in" + " a linkage-specification"); + + /* Module-purview imports must not be from source inclusion + [cpp.import]/7 */ + if (attrs && module_purview_p () && !global_purview_p () + && private_lookup_attribute ("__translated", + strlen ("__translated"), attrs)) + error_at (token->location, "post-module-declaration imports" + " must not be include-translated"); + else if ((mp_state == MP_PURVIEW_IMPORTS + || mp_state == MP_PRIVATE_IMPORTS) + && !token->main_source_p) + error_at (token->location, "post-module-declaration imports" + " must not be from header inclusion"); + + import_module (mod, token->location, exporting, attrs, parse_in); + } +} + +/* export-declaration. + + export declaration + export { declaration-seq-opt } */ + +static void +cp_parser_module_export (cp_parser *parser) +{ + gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT)); + cp_token *token = cp_lexer_consume_token (parser->lexer); + + if (!module_interface_p ()) + error_at (token->location, + "%qE may only occur after a module interface declaration", + token->u.value); + + bool braced = cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE); + + unsigned mk = module_kind; + if (module_exporting_p ()) + error_at (token->location, + "%qE may only occur once in an export declaration", + token->u.value); + module_kind |= MK_EXPORTING; + + if (braced) + { + cp_ensure_no_omp_declare_simd (parser); + cp_ensure_no_oacc_routine (parser); + + cp_lexer_consume_token (parser->lexer); + cp_parser_declaration_seq_opt (parser); + cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + } + else + { + /* Explicitly check if the next tokens might be a + module-directive line, so we can give a clearer error message + about why the directive will be rejected. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID__MODULE) + || cp_lexer_next_token_is_keyword (parser->lexer, RID__IMPORT) + || cp_lexer_next_token_is_keyword (parser->lexer, RID__EXPORT)) + error_at (token->location, "%<export%> not part of following" + " module-directive"); + cp_parser_declaration (parser, NULL_TREE); + } + + module_kind = mk; +} + /* Declarations [gram.dcl.dcl] */ -/* Parse an optional declaration-sequence. +/* Parse an optional declaration-sequence. TOP_LEVEL is true, if this + is the top-level declaration sequence. That affects whether we + deal with module-preamble. declaration-seq: declaration @@ -13550,6 +13910,14 @@ cp_parser_declaration_seq_opt (cp_parser* parser) C++17: deduction-guide + modules: + (all these are only allowed at the outermost level, check + that semantically, for better diagnostics) + module-declaration + module-export-declaration + module-import-declaration + export-declaration + GNU extension: declaration: @@ -13643,10 +14011,28 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs) else cp_parser_explicit_instantiation (parser); } - /* If the next token is `export', then we have a template - declaration. */ + /* If the next token is `export', it's new-style modules or + old-style template. */ else if (token1->keyword == RID_EXPORT) - cp_parser_template_declaration (parser, /*member_p=*/false); + { + if (!modules_p ()) + cp_parser_template_declaration (parser, /*member_p=*/false); + else + cp_parser_module_export (parser); + } + else if (token1->keyword == RID__EXPORT + || token1->keyword == RID__IMPORT + || token1->keyword == RID__MODULE) + { + bool exporting = token1->keyword == RID__EXPORT; + cp_token *next = exporting ? token2 : token1; + if (exporting) + cp_lexer_consume_token (parser->lexer); + if (next->keyword == RID__MODULE) + cp_parser_module_declaration (parser, MP_NOT_MODULE, exporting); + else + cp_parser_import_declaration (parser, MP_NOT_MODULE, exporting); + } /* If the next token is `extern', 'static' or 'inline' and the one after that is `template', we have a GNU extended explicit instantiation directive. */ @@ -16141,7 +16527,7 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p) else if (cxx_dialect < cxx20) warning (0, "keyword %<export%> is deprecated, and is ignored"); else - warning (0, "keyword %<export%> not implemented, and will be ignored"); + warning (0, "keyword %<export%> is enabled with %<-fmodules-ts%>"); } cp_parser_template_declaration_after_export (parser, member_p); @@ -19277,7 +19663,9 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, if (TREE_CODE (type) == TYPENAME_TYPE) warning (OPT_Wattributes, "attributes ignored on uninstantiated type"); - else if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type) + else if (tag_type != enum_type + && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM + && CLASSTYPE_TEMPLATE_INSTANTIATION (type) && ! processing_explicit_instantiation) warning (OPT_Wattributes, "attributes ignored on template instantiation"); @@ -19359,7 +19747,7 @@ cp_parser_enum_specifier (cp_parser* parser) bool is_unnamed = false; tree underlying_type = NULL_TREE; cp_token *type_start_token = NULL; - temp_override<bool> cleanup (parser->colon_corrects_to_scope_p, false); + auto cleanup = make_temp_override (parser->colon_corrects_to_scope_p, false); /* Parse tentatively so that we can back up if we don't find a enum-specifier. */ @@ -21025,6 +21413,7 @@ cp_parser_init_declarator (cp_parser* parser, bool is_non_constant_init; int ctor_dtor_or_conv_p; bool friend_p = cp_parser_friend_p (decl_specifiers); + bool static_p = decl_specifiers->storage_class == sc_static; tree pushed_scope = NULL_TREE; bool range_for_decl_p = false; bool saved_default_arg_ok_p = parser->default_arg_ok_p; @@ -21058,7 +21447,7 @@ cp_parser_init_declarator (cp_parser* parser, = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, flags, &ctor_dtor_or_conv_p, /*parenthesized_p=*/NULL, - member_p, friend_p, /*static_p=*/false); + member_p, friend_p, static_p); /* Gather up the deferred checks. */ stop_deferring_access_checks (); @@ -21734,7 +22123,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; - if (memfn) + if (memfn && !friend_p) /* DR 1207: 'this' is in scope after the cv-quals. */ inject_this_parameter (current_class_type, cv_quals); @@ -23008,7 +23397,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser, cp_token *token; bool ellipsis_p; - temp_override<bool> cleanup + auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p); if (!processing_specialization @@ -24170,7 +24559,9 @@ cp_parser_class_name (cp_parser *parser, where we first want to look up A<T>::a in the class of the object expression, as per [basic.lookup.classref]. */ tree scope = parser->scope ? parser->scope : parser->context->object_type; - if (scope == error_mark_node) + /* This only checks parser->scope to avoid duplicate errors; if + ->object_type is erroneous, go on to give a parse error. */ + if (parser->scope == error_mark_node) return error_mark_node; /* Any name names a type if we're following the `typename' keyword @@ -24322,7 +24713,6 @@ inject_parm_decls (tree decl) if (args && is_this_parameter (args)) { gcc_checking_assert (current_class_ptr == NULL_TREE); - current_class_ptr = NULL_TREE; current_class_ref = cp_build_fold_indirect_ref (args); current_class_ptr = args; } @@ -24579,7 +24969,6 @@ cp_parser_class_specifier_1 (cp_parser* parser) tree pushed_scope = NULL_TREE; unsigned ix; cp_default_arg_entry *e; - tree save_ccp, save_ccr; if (!type_definition_ok_p || any_erroneous_template_args_p (type)) { @@ -24620,31 +25009,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_funs_with_default_args, 0); - /* Now parse any NSDMIs. */ - save_ccp = current_class_ptr; - save_ccr = current_class_ref; - FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) - { - if (class_type != DECL_CONTEXT (decl)) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = DECL_CONTEXT (decl); - pushed_scope = push_scope (class_type); - } - inject_this_parameter (class_type, TYPE_UNQUALIFIED); - cp_parser_late_parsing_nsdmi (parser, decl); - } - vec_safe_truncate (unparsed_nsdmis, 0); - current_class_ptr = save_ccp; - current_class_ref = save_ccr; - if (pushed_scope) - pop_scope (pushed_scope); /* If there are noexcept-specifiers that have not yet been processed, - take care of them now. */ - class_type = NULL_TREE; - pushed_scope = NULL_TREE; + take care of them now. Do this before processing NSDMIs as they + may depend on noexcept-specifiers already having been processed. */ + tree save_ccp = current_class_ptr; + tree save_ccr = current_class_ref; FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl) { tree ctx = DECL_CONTEXT (decl); @@ -24662,7 +25032,9 @@ cp_parser_class_specifier_1 (cp_parser* parser) /* Make sure that any template parameters are in scope. */ maybe_begin_member_template_processing (decl); - /* Make sure that any member-function parameters are in scope. */ + /* Make sure that any member-function parameters are in scope. + This function doesn't expect ccp to be set. */ + current_class_ptr = current_class_ref = NULL_TREE; inject_parm_decls (decl); /* 'this' is not allowed in static member functions. */ @@ -24696,6 +25068,23 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_noexcepts, 0); + + /* Now parse any NSDMIs. */ + FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) + { + if (class_type != DECL_CONTEXT (decl)) + { + if (pushed_scope) + pop_scope (pushed_scope); + class_type = DECL_CONTEXT (decl); + pushed_scope = push_scope (class_type); + } + inject_this_parameter (class_type, TYPE_UNQUALIFIED); + cp_parser_late_parsing_nsdmi (parser, decl); + } + vec_safe_truncate (unparsed_nsdmis, 0); + current_class_ptr = save_ccp; + current_class_ref = save_ccr; if (pushed_scope) pop_scope (pushed_scope); @@ -25190,19 +25579,11 @@ cp_parser_class_head (cp_parser* parser, is valid. */ - /* Get the list of base-classes, if there is one. */ + /* Get the list of base-classes, if there is one. Defer access checking + until the entire list has been seen, as per [class.access.general]. */ + push_deferring_access_checks (dk_deferred); if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) - { - /* PR59482: enter the class scope so that base-specifiers are looked - up correctly. */ - if (type) - pushclass (type); - bases = cp_parser_base_clause (parser); - /* PR59482: get out of the previously pushed class scope so that the - subsequent pops pop the right thing. */ - if (type) - popclass (); - } + bases = cp_parser_base_clause (parser); else bases = NULL_TREE; @@ -25211,6 +25592,20 @@ cp_parser_class_head (cp_parser* parser, if (type && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) xref_basetypes (type, bases); + /* Now that all bases have been seen and attached to the class, check + accessibility of the types named in the base-clause. This must be + done relative to the class scope, so that we accept e.g. + + struct A { protected: struct B {}; }; + struct C : A::B, A {}; // OK: A::B is accessible via base A + + as per [class.access.general]. */ + if (type) + pushclass (type); + pop_to_parent_deferring_access_checks (); + if (type) + popclass (); + done: /* Leave the scope given by the nested-name-specifier. We will enter the class scope itself while processing the members. */ @@ -27115,7 +27510,7 @@ cp_parser_gnu_attributes_opt (cp_parser* parser) { tree attributes = NULL_TREE; - temp_override<bool> cleanup + auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p, false); while (true) @@ -27315,7 +27710,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) tree attribute, attr_id = NULL_TREE, arguments; cp_token *token; - temp_override<bool> cleanup + auto cleanup = make_temp_override (parser->auto_is_implicit_function_template_parm_p, false); /* First, parse name of the attribute, a.k.a attribute-token. */ @@ -29544,6 +29939,14 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, /* Finish the function. */ fn = finish_function (inline_p); + + if (modules_p () + && !inline_p + && TYPE_P (DECL_CONTEXT (fn)) + && (DECL_DECLARED_INLINE_P (fn) + || processing_template_decl)) + set_defining_module (fn); + /* Generate code for it, if necessary. */ expand_or_defer_fn (fn); /* Restore the saved values. */ @@ -30429,10 +30832,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) start_preparsed_function (member_function, NULL_TREE, SF_PRE_PARSED | SF_INCLASS_INLINE); - /* Don't do access checking if it is a templated function. */ - if (processing_template_decl) - push_deferring_access_checks (dk_no_check); - /* #pragma omp declare reduction needs special parsing. */ if (DECL_OMP_DECLARE_REDUCTION_P (member_function)) { @@ -30446,9 +30845,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) cp_parser_function_definition_after_declarator (parser, /*inline_p=*/true); - if (processing_template_decl) - pop_deferring_access_checks (); - /* Leave the scope of the containing function. */ if (function_scope) pop_function_context (); @@ -37016,6 +37412,52 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, } /* OpenMP 5.0: + detach ( event-handle ) */ + +static tree +cp_parser_omp_clause_detach (cp_parser *parser, tree list) +{ + matching_parens parens; + + if (!parens.require_open (parser)) + return list; + + cp_token *token; + tree name, decl; + + token = cp_lexer_peek_token (parser->lexer); + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + decl = error_mark_node; + else + { + if (identifier_p (name)) + decl = cp_parser_lookup_name_simple (parser, name, token->location); + else + decl = name; + if (decl == error_mark_node) + cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, + token->location); + } + + if (decl == error_mark_node + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + tree u = build_omp_clause (token->location, OMP_CLAUSE_DETACH); + OMP_CLAUSE_DECL (u) = decl; + OMP_CLAUSE_CHAIN (u) = list; + + return u; +} + +/* OpenMP 5.0: iterators ( iterators-definition ) iterators-definition: @@ -38074,6 +38516,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location); c_name = "depend"; break; + case PRAGMA_OMP_CLAUSE_DETACH: + clauses = cp_parser_omp_clause_detach (parser, clauses); + c_name = "detach"; + break; case PRAGMA_OMP_CLAUSE_MAP: clauses = cp_parser_omp_clause_map (parser, clauses); c_name = "map"; @@ -38198,6 +38644,42 @@ cp_parser_omp_structured_block (cp_parser *parser, bool *if_p) return finish_omp_structured_block (stmt); } +/* OpenMP 5.0: + # pragma omp allocate (list) [allocator(allocator)] */ + +static void +cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) +{ + tree allocator = NULL_TREE; + location_t loc = pragma_tok->location; + tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + matching_parens parens; + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + location_t cloc = cp_lexer_peek_token (parser->lexer)->location; + cp_lexer_consume_token (parser->lexer); + if (strcmp (p, "allocator") != 0) + error_at (cloc, "expected %<allocator%>"); + else if (parens.require_open (parser)) + { + allocator = cp_parser_assignment_expression (parser); + if (allocator == error_mark_node) + allocator = NULL_TREE; + parens.require_close (parser); + } + } + cp_parser_require_pragma_eol (parser, pragma_tok); + + if (allocator) + for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + + sorry_at (loc, "%<#pragma omp allocate%> not yet supported"); +} + /* OpenMP 2.5: # pragma omp atomic new-line expression-stmt @@ -40491,6 +40973,9 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, cclauses = cclauses_buf; cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_master (parser, pragma_tok, p_name, mask, + cclauses, if_p); block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); tree ret = cp_parser_omp_master (parser, pragma_tok, p_name, mask, @@ -40610,7 +41095,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) @@ -43835,6 +44321,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) case PRAGMA_OACC_WAIT: stmt = cp_parser_oacc_wait (parser, pragma_tok); break; + case PRAGMA_OMP_ALLOCATE: + cp_parser_omp_allocate (parser, pragma_tok); + return; case PRAGMA_OMP_ATOMIC: cp_parser_omp_atomic (parser, pragma_tok, false); return; @@ -44480,7 +44969,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) goto bad_stmt; cp_parser_omp_construct (parser, pragma_tok, if_p); return true; - + case PRAGMA_OMP_ALLOCATE: + cp_parser_omp_allocate (parser, pragma_tok); + return false; case PRAGMA_OACC_ATOMIC: case PRAGMA_OACC_CACHE: case PRAGMA_OACC_DATA: diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index ec487ea..d587cf2 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -1,5 +1,5 @@ /* Data structures and function exported by the C++ Parser. - Copyright (C) 2010-2020 Free Software Foundation, Inc. + Copyright (C) 2010-2021 Free Software Foundation, Inc. This file is part of GCC. @@ -58,7 +58,8 @@ struct GTY (()) cp_token { deleted. */ bool purged_p : 1; bool tree_check_p : 1; - /* 4 unused bits. */ + bool main_source_p : 1; + /* 3 unused bits. */ /* The location at which this token was found. */ location_t location; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2d3ab92..aa1687a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1,5 +1,5 @@ /* Handle parameterized types (templates) for GNU -*- C++ -*-. - Copyright (C) 1992-2020 Free Software Foundation, Inc. + Copyright (C) 1992-2021 Free Software Foundation, Inc. Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing. Rewritten by Jason Merrill (jason@cygnus.com). @@ -960,6 +960,9 @@ maybe_new_partial_specialization (tree type) TREE_PRIVATE (d) = (current_access_specifier == access_private_node); TREE_PROTECTED (d) = (current_access_specifier == access_protected_node); + set_instantiating_module (d); + DECL_MODULE_EXPORT_P (d) = DECL_MODULE_EXPORT_P (tmpl); + return t; } @@ -1704,9 +1707,11 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, return spec; } -/* Returns true iff two spec_entry nodes are equivalent. */ - +/* Restricts tree and type comparisons. */ int comparing_specializations; +int comparing_dependent_aliases; + +/* Returns true iff two spec_entry nodes are equivalent. */ bool spec_hasher::equal (spec_entry *e1, spec_entry *e2) @@ -1714,6 +1719,7 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2) int equal; ++comparing_specializations; + ++comparing_dependent_aliases; equal = (e1->tmpl == e2->tmpl && comp_template_args (e1->args, e2->args)); if (equal && flag_concepts @@ -1728,6 +1734,7 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2) tree c2 = e2->spec ? get_constraints (e2->spec) : NULL_TREE; equal = equivalent_constraints (c1, c2); } + --comparing_dependent_aliases; --comparing_specializations; return equal; @@ -4921,6 +4928,17 @@ build_template_decl (tree decl, tree parms, bool member_template_p) DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl); DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p; + if (modules_p ()) + { + /* Propagate module information from the decl. */ + DECL_MODULE_EXPORT_P (tmpl) = DECL_MODULE_EXPORT_P (decl); + if (DECL_LANG_SPECIFIC (decl)) + { + DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (decl); + gcc_checking_assert (!DECL_MODULE_IMPORT_P (decl)); + } + } + return tmpl; } @@ -6501,7 +6519,11 @@ complex_alias_template_p (const_tree tmpl) tree dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs) { - if (!TYPE_P (t) || !typedef_variant_p (t)) + if (t == error_mark_node) + return NULL_TREE; + gcc_assert (TYPE_P (t)); + + if (!typedef_variant_p (t)) return NULL_TREE; tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t); @@ -9151,6 +9173,18 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */) if (class_nttp_const_wrapper_p (ot)) ot = TREE_OPERAND (ot, 0); + /* DR 1558: Don't treat an alias template specialization with dependent + arguments as equivalent to its underlying type when used as a template + argument; we need them to be distinct so that we substitute into the + specialization arguments at instantiation time. And aliases can't be + equivalent without being ==, so we don't need to look any deeper. + + During partial ordering, however, we need to treat them normally so we can + order uses of the same alias with different cv-qualification (79960). */ + auto cso = make_temp_override (comparing_dependent_aliases); + if (!partial_order) + ++comparing_dependent_aliases; + if (TREE_CODE (nt) == TREE_VEC || TREE_CODE (ot) == TREE_VEC) /* For member templates */ return TREE_CODE (ot) == TREE_CODE (nt) && comp_template_args (ot, nt); @@ -9168,21 +9202,7 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */) { if (!(TYPE_P (nt) && TYPE_P (ot))) return false; - /* Don't treat an alias template specialization with dependent - arguments as equivalent to its underlying type when used as a - template argument; we need them to be distinct so that we - substitute into the specialization arguments at instantiation - time. And aliases can't be equivalent without being ==, so - we don't need to look any deeper. - - During partial ordering, however, we need to treat them normally so - that we can order uses of the same alias with different - cv-qualification (79960). */ - if (!partial_order - && (TYPE_ALIAS_P (nt) || TYPE_ALIAS_P (ot))) - return false; - else - return same_type_p (ot, nt); + return same_type_p (ot, nt); } else { @@ -9773,6 +9793,15 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, return error_mark_node; gen_tmpl = most_general_template (templ); + if (modules_p ()) + { + tree origin = get_originating_module_decl (gen_tmpl); + load_pending_specializations (CP_DECL_CONTEXT (origin), + DECL_NAME (origin)); + if (DECL_MODULE_PENDING_SPECIALIZATIONS_P (gen_tmpl)) + lazy_load_specializations (gen_tmpl); + } + parmlist = DECL_TEMPLATE_PARMS (gen_tmpl); parm_depth = TMPL_PARMS_DEPTH (parmlist); arg_depth = TMPL_ARGS_DEPTH (arglist); @@ -9993,6 +10022,12 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (template_type)); } + set_instantiating_module (type_decl); + /* Although GEN_TMPL is the TEMPLATE_DECL, it has the same value + of export flag. We want to propagate this because it might + be a friend declaration that pushes a new hidden binding. */ + DECL_MODULE_EXPORT_P (type_decl) = DECL_MODULE_EXPORT_P (gen_tmpl); + if (CLASS_TYPE_P (template_type)) { TREE_PRIVATE (type_decl) @@ -10775,14 +10810,16 @@ uses_template_parms (tree t) return dependent_p; } -/* Returns true iff current_function_decl is an incompletely instantiated +/* Returns true iff we're processing an incompletely instantiated function template. Useful instead of processing_template_decl because the latter is set to 0 during instantiate_non_dependent_expr. */ bool in_template_function (void) { - tree fn = current_function_decl; + /* Inspect the less volatile cfun->decl instead of current_function_decl; + the latter might get set for e.g. access checking during satisfaction. */ + tree fn = cfun ? cfun->decl : NULL_TREE; bool ret; ++processing_template_decl; ret = (fn && DECL_LANG_SPECIFIC (fn) @@ -10909,6 +10946,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) new_level->errors = errorcount + sorrycount; new_level->next = NULL; new_level->refcount = 0; + new_level->path = new_level->visible = nullptr; set_refcount_ptr (new_level->next, current_tinst_level); set_refcount_ptr (current_tinst_level, new_level); @@ -11792,17 +11830,14 @@ instantiate_class_template_1 (tree type) || COMPLETE_OR_OPEN_TYPE_P (TYPE_CONTEXT (type))); base_list = NULL_TREE; + /* Defer access checking while we substitute into the types named in + the base-clause. */ + push_deferring_access_checks (dk_deferred); if (BINFO_N_BASE_BINFOS (pbinfo)) { tree pbase_binfo; - tree pushed_scope; int i; - /* We must enter the scope containing the type, as that is where - the accessibility of types named in dependent bases are - looked up from. */ - pushed_scope = push_scope (CP_TYPE_CONTEXT (type)); - /* Substitute into each of the bases to determine the actual basetypes. */ for (i = 0; BINFO_BASE_ITERATE (pbinfo, i, pbase_binfo); i++) @@ -11844,9 +11879,6 @@ instantiate_class_template_1 (tree type) /* The list is now in reverse order; correct that. */ base_list = nreverse (base_list); - - if (pushed_scope) - pop_scope (pushed_scope); } /* Now call xref_basetypes to set up all the base-class information. */ @@ -11864,6 +11896,13 @@ instantiate_class_template_1 (tree type) class, except we also need to push the enclosing classes. */ push_nested_class (type); + /* Now check accessibility of the types named in its base-clause, + relative to the scope of the class. */ + pop_to_parent_deferring_access_checks (); + + /* A vector to hold members marked with attribute used. */ + auto_vec<tree> used; + /* Now members are processed in the order of declaration. */ for (member = CLASSTYPE_DECL_LIST (pattern); member; member = TREE_CHAIN (member)) @@ -11937,7 +11976,7 @@ instantiate_class_template_1 (tree type) finish_member_declaration (r); /* Instantiate members marked with attribute used. */ if (r != error_mark_node && DECL_PRESERVE_P (r)) - mark_used (r); + used.safe_push (r); if (TREE_CODE (r) == FUNCTION_DECL && DECL_OMP_DECLARE_REDUCTION_P (r)) cp_check_omp_declare_reduction (r); @@ -12003,7 +12042,7 @@ instantiate_class_template_1 (tree type) /*flags=*/0); /* Instantiate members marked with attribute used. */ if (r != error_mark_node && DECL_PRESERVE_P (r)) - mark_used (r); + used.safe_push (r); } else if (TREE_CODE (r) == FIELD_DECL) { @@ -12194,6 +12233,11 @@ instantiate_class_template_1 (tree type) if (TYPE_CONTAINS_VPTR_P (type) && CLASSTYPE_KEY_METHOD (type)) vec_safe_push (keyed_classes, type); + /* Now that we've gone through all the members, instantiate those + marked with attribute used. */ + for (tree x : used) + mark_used (x); + return type; } @@ -13910,6 +13954,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (!DECL_DELETED_FN (r)) DECL_INITIAL (r) = NULL_TREE; DECL_CONTEXT (r) = ctx; + set_instantiating_module (r); /* Handle explicit(dependent-expr). */ if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t)) @@ -14233,6 +14278,24 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, TREE_TYPE (r) = TREE_TYPE (inner); DECL_CONTEXT (r) = DECL_CONTEXT (inner); + if (modules_p ()) + { + /* Propagate module information from the decl. */ + DECL_MODULE_EXPORT_P (r) = DECL_MODULE_EXPORT_P (inner); + if (DECL_LANG_SPECIFIC (inner)) + { + DECL_MODULE_PURVIEW_P (r) = DECL_MODULE_PURVIEW_P (inner); + /* If this is a constrained template, the above tsubst of + inner can find the unconstrained template, which may have + come from an import. This is ok, because we don't + register this instantiation (see below). */ + gcc_checking_assert (!DECL_MODULE_IMPORT_P (inner) + || (TEMPLATE_PARMS_CONSTRAINTS + (DECL_TEMPLATE_PARMS (t)))); + DECL_MODULE_IMPORT_P (r) = false; + } + } + DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE; DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE; @@ -14787,6 +14850,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) SET_DECL_ASSEMBLER_NAME (r, NULL_TREE); if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL)) SET_DECL_RTL (r, NULL); + set_instantiating_module (r); + /* The initializer must not be expanded until it is required; see [temp.inst]. */ DECL_INITIAL (r) = NULL_TREE; @@ -14843,10 +14908,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) { DECL_ORIGINAL_TYPE (r) = NULL_TREE; set_underlying_type (r); - if (TYPE_DECL_ALIAS_P (r)) - /* An alias template specialization can be dependent - even if its underlying type is not. */ - TYPE_DEPENDENT_P_VALID (TREE_TYPE (r)) = false; } layout_decl (r, 0); @@ -15636,6 +15697,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else if (tree pl = CLASS_PLACEHOLDER_TEMPLATE (t)) { pl = tsubst_copy (pl, args, complain, in_decl); + if (TREE_CODE (pl) == TEMPLATE_TEMPLATE_PARM) + pl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (pl); CLASS_PLACEHOLDER_TEMPLATE (r) = pl; } } @@ -15948,13 +16011,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) But, such constructs have already been resolved by this point, so here CTX really should have complete type, unless it's a partial instantiation. */ - ctx = complete_type (ctx); - if (!COMPLETE_TYPE_P (ctx)) - { - if (complain & tf_error) - cxx_incomplete_type_error (NULL_TREE, ctx); - return error_mark_node; - } + if (!complete_type_or_maybe_complain (ctx, NULL_TREE, complain)) + return error_mark_node; } f = make_typename_type (ctx, f, typename_type, @@ -16138,6 +16196,16 @@ tsubst_baselink (tree baselink, tree object_type, if (IDENTIFIER_CONV_OP_P (name)) name = make_conv_op_name (optype); + /* See maybe_dependent_member_ref. */ + if (dependent_scope_p (qualifying_scope)) + { + if (template_id_p) + name = build2 (TEMPLATE_ID_EXPR, unknown_type_node, name, + template_args); + return build_qualified_name (NULL_TREE, qualifying_scope, name, + /* ::template */false); + } + if (name == complete_dtor_identifier) /* Treat as-if non-dependent below. */ dependent_p = false; @@ -16747,7 +16815,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) { tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - return cp_build_bit_cast (EXPR_LOCATION (t), type, op0, complain); + r = build_min (BIT_CAST_EXPR, type, op0); + SET_EXPR_LOCATION (r, EXPR_LOCATION (t)); + return r; } case SIZEOF_EXPR: @@ -17303,6 +17373,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_VECTOR: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_DETACH: OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -18070,18 +18141,33 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, finish_label_decl (DECL_NAME (decl)); else if (TREE_CODE (decl) == USING_DECL) { - /* We cannot have a member-using decl here (until 'using - enum T' is a thing). */ - gcc_checking_assert (!DECL_DEPENDENT_P (decl)); - - /* This must be a non-dependent using-decl, and we'll have - used the names it found during template parsing. We do - not want to do the lookup again, because we might not - find the things we found then. (Again, using enum T - might mean we have to do things here.) */ tree scope = USING_DECL_SCOPE (decl); - gcc_checking_assert (scope - == tsubst (scope, args, complain, in_decl)); + if (DECL_DEPENDENT_P (decl)) + { + scope = tsubst (scope, args, complain, in_decl); + if (!MAYBE_CLASS_TYPE_P (scope) + && TREE_CODE (scope) != ENUMERAL_TYPE) + { + if (complain & tf_error) + error_at (DECL_SOURCE_LOCATION (decl), "%qT is not a " + "class, namespace, or enumeration", scope); + return error_mark_node; + } + finish_nonmember_using_decl (scope, DECL_NAME (decl)); + } + else + { + /* This is a non-dependent using-decl, and we'll have + used the names it found during template parsing. We do + not want to do the lookup again, because we might not + find the things we found then. */ + gcc_checking_assert (scope == tsubst (scope, args, + complain, in_decl)); + /* We still need to push the bindings so that we can look up + this name later. */ + push_using_decl_bindings (DECL_NAME (decl), + USING_DECL_DECLS (decl)); + } } else if (is_capture_proxy (decl) && !DECL_TEMPLATE_INSTANTIATION (current_function_decl)) @@ -18163,6 +18249,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, bool const_init = false; unsigned int cnt = 0; tree first = NULL_TREE, ndecl = error_mark_node; + tree asmspec_tree = NULL_TREE; maybe_push_decl (decl); if (VAR_P (decl) @@ -18186,7 +18273,18 @@ 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, 0); + if (VAR_P (decl) && DECL_HARD_REGISTER (pattern_decl)) + { + tree id = DECL_ASSEMBLER_NAME (pattern_decl); + const char *asmspec = IDENTIFIER_POINTER (id); + gcc_assert (asmspec[0] == '*'); + asmspec_tree + = build_string (IDENTIFIER_LENGTH (id) - 1, + asmspec + 1); + TREE_TYPE (asmspec_tree) = char_array_type_node; + } + + cp_finish_decl (decl, init, const_init, asmspec_tree, 0); if (ndecl != error_mark_node) cp_finish_decomp (ndecl, first, cnt); @@ -19582,6 +19680,13 @@ tsubst_copy_and_build (tree t, RETURN (r); } + case BIT_CAST_EXPR: + { + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree op0 = RECUR (TREE_OPERAND (t, 0)); + RETURN (cp_build_bit_cast (EXPR_LOCATION (t), type, op0, complain)); + } + case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0), @@ -20864,6 +20969,15 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (tmpl)), targ_ptr)); + if (modules_p ()) + { + tree origin = get_originating_module_decl (gen_tmpl); + load_pending_specializations (CP_DECL_CONTEXT (origin), + DECL_NAME (origin)); + if (DECL_MODULE_PENDING_SPECIALIZATIONS_P (gen_tmpl)) + lazy_load_specializations (gen_tmpl); + } + /* It would be nice to avoid hashing here and then again in tsubst_decl, but it doesn't seem to be on the hot path. */ spec = retrieve_specialization (gen_tmpl, targ_ptr, 0); @@ -20949,6 +21063,8 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) DECL_TI_TEMPLATE (fndecl) = tmpl; DECL_TI_ARGS (fndecl) = targ_ptr; + set_instantiating_module (fndecl); + /* Now we know the specialization, compute access previously deferred. Do no access control for inheriting constructors, as we already checked access for the inherited constructor. */ @@ -21031,6 +21147,17 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain) tree r = instantiate_template (tmpl, args, complain); pop_tinst_level (); + if (tree d = dependent_alias_template_spec_p (TREE_TYPE (r), nt_opaque)) + { + /* An alias template specialization can be dependent + even if its underlying type is not. */ + TYPE_DEPENDENT_P (d) = true; + TYPE_DEPENDENT_P_VALID (d) = true; + /* Sometimes a dependent alias spec is equivalent to its expansion, + sometimes not. So always use structural_comptypes. */ + SET_TYPE_STRUCTURAL_EQUALITY (d); + } + return r; } @@ -22313,6 +22440,9 @@ resolve_overloaded_unification (tree tparms, --function_depth; } + if (flag_noexcept_type) + maybe_instantiate_noexcept (fn, tf_none); + elem = TREE_TYPE (fn); if (try_one_overload (tparms, targs, tempargs, parm, elem, strict, sub_strict, addr_p, explain_p) @@ -23521,13 +23651,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* We haven't deduced the type of this parameter yet. */ if (cxx_dialect >= cxx17 /* We deduce from array bounds in try_array_deduction. */ - && !(strict & UNIFY_ALLOW_INTEGER)) + && !(strict & UNIFY_ALLOW_INTEGER) + && TEMPLATE_PARM_LEVEL (parm) <= TMPL_ARGS_DEPTH (targs)) { /* Deduce it from the non-type argument. */ tree atype = TREE_TYPE (arg); RECUR_AND_CHECK_FAILURE (tparms, targs, tparm, atype, UNIFY_ALLOW_NONE, explain_p); + /* Now check whether the type of this parameter is still + dependent, and give up if so. */ + ++processing_template_decl; + tparm = tsubst (tparm, targs, tf_none, NULL_TREE); + --processing_template_decl; + if (uses_template_parms (tparm)) + return unify_success (explain_p); } else /* Try again later. */ @@ -25372,7 +25510,8 @@ always_instantiate_p (tree decl) bool maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) { - tree fntype, spec, noex; + if (fn == error_mark_node) + return false; /* Don't instantiate a noexcept-specification from template context. */ if (processing_template_decl @@ -25391,13 +25530,13 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) return !DECL_MAYBE_DELETED (fn); } - fntype = TREE_TYPE (fn); - spec = TYPE_RAISES_EXCEPTIONS (fntype); + tree fntype = TREE_TYPE (fn); + tree spec = TYPE_RAISES_EXCEPTIONS (fntype); if (!spec || !TREE_PURPOSE (spec)) return true; - noex = TREE_PURPOSE (spec); + tree noex = TREE_PURPOSE (spec); if (TREE_CODE (noex) != DEFERRED_NOEXCEPT && TREE_CODE (noex) != DEFERRED_PARSE) return true; @@ -28035,6 +28174,8 @@ finish_concept_definition (cp_expr id, tree init) DECL_CONTEXT (decl) = current_scope (); DECL_INITIAL (decl) = init; + set_originating_module (decl, false); + /* Push the enclosing template. */ return push_template_decl (decl); } @@ -29668,29 +29809,27 @@ walk_specializations (bool decls_p, fn (decls_p, *iter, data); } -/* Lookup the specialization of TMPL, ARGS in the decl or type - specialization table. Return what's there, or if SPEC is non-null, - add it and return NULL. */ +/* Lookup the specialization of *ELT, in the decl or type + specialization table. Return the SPEC that's already there (NULL if + nothing). If INSERT is true, and there was nothing, add the new + spec. */ tree -match_mergeable_specialization (bool decl_p, tree tmpl, tree args, tree spec) +match_mergeable_specialization (bool decl_p, spec_entry *elt, bool insert) { - spec_entry elt = {tmpl, args, spec}; hash_table<spec_hasher> *specializations = decl_p ? decl_specializations : type_specializations; - hashval_t hash = spec_hasher::hash (&elt); + hashval_t hash = spec_hasher::hash (elt); spec_entry **slot - = specializations->find_slot_with_hash (&elt, hash, - spec ? INSERT : NO_INSERT); - spec_entry *entry = slot ? *slot: NULL; - - if (entry) - return entry->spec; + = specializations->find_slot_with_hash (elt, hash, + insert ? INSERT : NO_INSERT); + if (slot && *slot) + return (*slot)->spec; - if (spec) + if (insert) { - entry = ggc_alloc<spec_entry> (); - *entry = elt; + auto entry = ggc_alloc<spec_entry> (); + *entry = *elt; *slot = entry; } diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index f8d2208..e06fe6f 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -1,5 +1,5 @@ /* Prints out trees in human readable form. - Copyright (C) 1992-2020 Free Software Foundation, Inc. + Copyright (C) 1992-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -59,6 +59,42 @@ cxx_print_decl (FILE *file, tree node, int indent) bool need_indent = true; + if (TREE_CODE (node) == FUNCTION_DECL + || TREE_CODE (node) == VAR_DECL + || TREE_CODE (node) == TYPE_DECL + || TREE_CODE (node) == TEMPLATE_DECL + || TREE_CODE (node) == CONCEPT_DECL + || TREE_CODE (node) == NAMESPACE_DECL) + { + unsigned m = 0; + if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_IMPORT_P (node)) + m = get_importing_module (node, true); + + if (const char *name = m == ~0u ? "" : module_name (m, true)) + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " module %d:%s", m, name); + need_indent = false; + } + + if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_PURVIEW_P (node)) + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " purview"); + need_indent = false; + } + } + + if (DECL_MODULE_EXPORT_P (node)) + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " exported"); + need_indent = false; + } + if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node)) { if (need_indent) diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index d628862..d3cb9ad 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1,5 +1,5 @@ /* RunTime Type Identification - Copyright (C) 1995-2020 Free Software Foundation, Inc. + Copyright (C) 1995-2021 Free Software Foundation, Inc. Mostly written by Jason Merrill (jason@cygnus.com). This file is part of GCC. @@ -143,16 +143,20 @@ static bool typeinfo_in_lib_p (tree); static int doing_runtime = 0; -static void +static unsigned push_abi_namespace (void) { push_nested_namespace (abi_node); push_visibility ("default", 2); + unsigned flags = module_kind; + module_kind = 0; + return flags; } static void -pop_abi_namespace (void) +pop_abi_namespace (unsigned flags) { + module_kind = flags; pop_visibility (2); pop_nested_namespace (abi_node); } @@ -765,7 +769,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr, dcast_fn = dynamic_cast_node; if (!dcast_fn) { - push_abi_namespace (); + unsigned flags = push_abi_namespace (); tree tinfo_ptr = xref_tag (class_type, get_identifier ("__class_type_info")); tinfo_ptr = cp_build_qualified_type (tinfo_ptr, TYPE_QUAL_CONST); @@ -780,7 +784,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr, NULL_TREE)); dcast_fn = (build_library_fn_ptr (fn_name, fn_type, ECF_LEAF | ECF_PURE | ECF_NOTHROW)); - pop_abi_namespace (); + pop_abi_namespace (flags); dynamic_cast_node = dcast_fn; } result = build_cxx_call (dcast_fn, 4, elems, complain); @@ -954,11 +958,11 @@ tinfo_base_init (tinfo_s *ti, tree target) vtable_ptr = ti->vtable; if (!vtable_ptr) { - push_abi_namespace (); + int flags = push_abi_namespace (); tree real_type = xref_tag (class_type, ti->name); tree real_decl = TYPE_NAME (real_type); DECL_SOURCE_LOCATION (real_decl) = BUILTINS_LOCATION; - pop_abi_namespace (); + pop_abi_namespace (flags); if (!COMPLETE_TYPE_P (real_type)) { diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 8a1de7c..7b18368 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1,6 +1,6 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -122,6 +122,41 @@ dfs_lookup_base (tree binfo, void *data_) return NULL_TREE; } +/* This deals with bug PR17314. + + DECL is a declaration and BINFO represents a class that has attempted (but + failed) to access DECL. + + Examine the parent binfos of BINFO and determine whether any of them had + private access to DECL. If they did, return the parent binfo. This helps + in figuring out the correct error message to show (if the parents had + access, it's their fault for not giving sufficient access to BINFO). + + If no parents had access, return NULL_TREE. */ + +tree +get_parent_with_private_access (tree decl, tree binfo) +{ + /* Only BINFOs should come through here. */ + gcc_assert (TREE_CODE (binfo) == TREE_BINFO); + + tree base_binfo = NULL_TREE; + + /* Iterate through immediate parent classes. */ + for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + /* This parent had private access. Therefore that's why BINFO can't + access DECL. */ + if (access_in_type (BINFO_TYPE (base_binfo), decl) == ak_private) + return base_binfo; + } + + /* None of the parents had access. Note: it's impossible for one of the + parents to have had public or protected access to DECL, since then + BINFO would have been able to access DECL too. */ + return NULL_TREE; +} + /* Returns true if type BASE is accessible in T. (BASE is known to be a (possibly non-proper) base class of T.) If CONSIDER_LOCAL_P is true, consider any special access of the current scope, or access @@ -698,6 +733,14 @@ friend_accessible_p (tree scope, tree decl, tree type, tree otype) if (DECL_CLASS_SCOPE_P (scope) && friend_accessible_p (DECL_CONTEXT (scope), decl, type, otype)) return 1; + /* Perhaps SCOPE is a friend function defined inside a class from which + DECL is accessible. Checking this is necessary only when the class + is dependent, for otherwise add_friend will already have added the + class to SCOPE's DECL_BEFRIENDING_CLASSES. */ + if (tree fctx = DECL_FRIEND_CONTEXT (scope)) + if (dependent_type_p (fctx) + && protected_accessible_p (decl, fctx, type, otype)) + return 1; } /* Maybe scope's template is a friend. */ @@ -902,7 +945,7 @@ struct lookup_field_info { const char *errstr; }; -/* Nonzero for a class member means that it is shared between all objects +/* True for a class member means that it is shared between all objects of that class. [class.member.lookup]:If the resulting set of declarations are not all @@ -912,25 +955,27 @@ struct lookup_field_info { This function checks that T contains no non-static members. */ -int +bool shared_member_p (tree t) { - if (VAR_P (t) || TREE_CODE (t) == TYPE_DECL \ + if (VAR_P (t) || TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == CONST_DECL) - return 1; + return true; if (is_overloaded_fn (t)) { for (ovl_iterator iter (get_fns (t)); iter; ++iter) { tree decl = strip_using_decl (*iter); - /* We don't expect or support dependent decls. */ - gcc_assert (TREE_CODE (decl) != USING_DECL); + if (TREE_CODE (decl) == USING_DECL) + /* Conservatively assume a dependent using-declaration + might resolve to a non-static member. */ + return false; if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) - return 0; + return false; } - return 1; + return true; } - return 0; + return false; } /* Routine to see if the sub-object denoted by the binfo PARENT can be diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d33ef42..7383446 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3,7 +3,7 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998-2020 Free Software Foundation, Inc. + Copyright (C) 1998-2021 Free Software Foundation, Inc. Written by Mark Mitchell (mmitchell@usa.net) based on code found formerly in parse.y and pt.c. @@ -316,7 +316,36 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl, if (flag_new_inheriting_ctors) diag_decl = strip_inheriting_ctors (diag_decl); if (complain & tf_error) - complain_about_access (decl, diag_decl, true); + { + /* We will usually want to point to the same place as + diag_decl but not always. */ + tree diag_location = diag_decl; + access_kind parent_access = ak_none; + + /* See if any of BASETYPE_PATH's parents had private access + to DECL. If they did, that will tell us why we don't. */ + tree parent_binfo = get_parent_with_private_access (decl, + basetype_path); + + /* If a parent had private access, then the diagnostic + location DECL should be that of the parent class, since it + failed to give suitable access by using a private + inheritance. But if DECL was actually defined in the parent, + it wasn't privately inherited, and so we don't need to do + this, and complain_about_access will figure out what to + do. */ + if (parent_binfo != NULL_TREE + && (context_for_name_lookup (decl) + != BINFO_TYPE (parent_binfo))) + { + diag_location = TYPE_NAME (BINFO_TYPE (parent_binfo)); + parent_access = ak_private; + } + + /* Finally, generate an error message. */ + complain_about_access (decl, diag_decl, diag_location, true, + parent_access); + } if (afi) afi->record_access_failure (basetype_path, decl, diag_decl); return false; @@ -2107,14 +2136,24 @@ check_accessibility_of_qualified_id (tree decl, /* If the reference is to a non-static member of the current class, treat it as if it were referenced through `this'. */ - tree ct; if (DECL_NONSTATIC_MEMBER_P (decl) - && current_class_ptr - && DERIVED_FROM_P (scope, ct = current_nonlambda_class_type ())) - qualifying_type = ct; + && current_class_ptr) + if (tree current = current_nonlambda_class_type ()) + { + if (dependent_type_p (current)) + /* In general we can't know whether this access goes through + `this' until instantiation time. Punt now, or else we might + create a deferred access check that's not relative to `this' + when it ought to be. We'll check this access again after + substitution, e.g. from tsubst_qualified_id. */ + return true; + + if (DERIVED_FROM_P (scope, current)) + qualifying_type = current; + } /* Otherwise, use the type indicated by the nested-name-specifier. */ - else + if (!qualifying_type) qualifying_type = nested_name_specifier; } else @@ -2204,8 +2243,7 @@ finish_qualified_id_expr (tree qualifying_class, { /* See if any of the functions are non-static members. */ /* If so, the expression may be relative to 'this'. */ - if ((type_dependent_expression_p (expr) - || !shared_member_p (expr)) + if (!shared_member_p (expr) && current_class_ptr && DERIVED_FROM_P (qualifying_class, current_nonlambda_class_type ())) @@ -3220,6 +3258,19 @@ begin_class_definition (tree t) t = make_class_type (TREE_CODE (t)); pushtag (TYPE_IDENTIFIER (t), t); } + + if (modules_p ()) + { + if (!module_may_redeclare (TYPE_NAME (t))) + { + error ("cannot declare %qD in a different module", TYPE_NAME (t)); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), "declared here"); + return error_mark_node; + } + set_instantiating_module (TYPE_NAME (t)); + set_defining_module (TYPE_NAME (t)); + } + maybe_process_partial_specialization (t); pushclass (t); TYPE_BEING_DEFINED (t) = 1; @@ -4506,7 +4557,8 @@ expand_or_defer_fn_1 (tree fn) it out, even though we haven't. */ TREE_ASM_WRITTEN (fn) = 1; /* If this is a constexpr function, keep DECL_SAVED_TREE. */ - if (!DECL_DECLARED_CONSTEXPR_P (fn)) + if (!DECL_DECLARED_CONSTEXPR_P (fn) + && !(modules_p () && DECL_DECLARED_INLINE_P (fn))) DECL_SAVED_TREE (fn) = NULL_TREE; return false; } @@ -6377,6 +6429,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) has been seen, -2 if mixed inscan/normal reduction diagnosed. */ int reduction_seen = 0; bool allocate_seen = false; + bool detach_seen = false; + bool mergeable_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -7394,6 +7448,42 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } } break; + case OMP_CLAUSE_DETACH: + t = OMP_CLAUSE_DECL (c); + if (detach_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "too many %qs clauses on a task construct", + "detach"); + remove = true; + break; + } + else if (error_operand_p (t)) + { + remove = true; + break; + } + else + { + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + if (!type_dependent_expression_p (t) + && (!INTEGRAL_TYPE_P (type) + || TREE_CODE (type) != ENUMERAL_TYPE + || TYPE_NAME (type) == NULL_TREE + || (DECL_NAME (TYPE_NAME (type)) + != get_identifier ("omp_event_handle_t")))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<detach%> clause event handle " + "has type %qT rather than " + "%<omp_event_handle_t%>", + type); + remove = true; + } + detach_seen = true; + cxx_mark_addressable (t); + } + break; case OMP_CLAUSE_MAP: case OMP_CLAUSE_TO: @@ -7925,7 +8015,6 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_DEFAULT: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: - case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_FOR: case OMP_CLAUSE_SECTIONS: @@ -7944,6 +8033,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_FINALIZE: break; + case OMP_CLAUSE_MERGEABLE: + mergeable_seen = true; + break; + case OMP_CLAUSE_TILE: for (tree list = OMP_CLAUSE_TILE_LIST (c); !remove && list; list = TREE_CHAIN (list)) @@ -8181,6 +8274,17 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_DETACH: + if (mergeable_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<detach%> clause must not be used together with " + "%<mergeable%> clause"); + *pc = OMP_CLAUSE_CHAIN (c); + continue; + } + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOWAIT: if (copyprivate_seen) { @@ -8341,6 +8445,19 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } } + if (detach_seen + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == t) + { + error_at (OMP_CLAUSE_LOCATION (c), + "the event handle of a %<detach%> clause " + "should not be in a data-sharing clause"); + remove = true; + } + /* We're interested in the base element, not arrays. */ inner_type = type = TREE_TYPE (t); if ((need_complete_type @@ -9991,6 +10108,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, return error_mark_node; } + /* decltype is an unevaluated context. */ + cp_unevaluated u; + /* Depending on the resolution of DR 1172, we may later need to distinguish instantiation-dependent but not type-dependent expressions so that, say, A<decltype(sizeof(T))>::U doesn't require 'typename'. */ @@ -10006,9 +10126,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, } else if (processing_template_decl) { - ++cp_unevaluated_operand; expr = instantiate_non_dependent_expr_sfinae (expr, complain); - --cp_unevaluated_operand; if (expr == error_mark_node) return error_mark_node; } @@ -10747,6 +10865,10 @@ cp_build_bit_cast (location_t loc, tree type, tree arg, tree ret = build_min (BIT_CAST_EXPR, type, arg); SET_EXPR_LOCATION (ret, loc); + + if (!processing_template_decl && CLASS_TYPE_P (type)) + ret = get_target_expr_sfinae (ret, complain); + return ret; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d9fa505..2e5a1f1 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1,5 +1,5 @@ /* Language-dependent node constructors for parse phase of GNU compiler. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -787,7 +787,15 @@ build_vec_init_expr (tree type, tree init, tsubst_flags_t complain) { tree slot; bool value_init = false; - tree elt_init = build_vec_init_elt (type, init, complain); + tree elt_init; + if (init && TREE_CODE (init) == CONSTRUCTOR) + { + gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (init)); + /* We built any needed constructor calls in digest_init. */ + elt_init = init; + } + else + elt_init = build_vec_init_elt (type, init, complain); if (init == void_type_node) { @@ -1332,10 +1340,12 @@ cp_build_qualified_type_real (tree type, if (!t) { - gcc_checking_assert (TYPE_DEPENDENT_P_VALID (type) - || !dependent_type_p (type)); + /* If we already know the dependentness, tell the array type + constructor. This is important for module streaming, as we cannot + dynamically determine that on read in. */ t = build_cplus_array_type (element_type, TYPE_DOMAIN (type), - TYPE_DEPENDENT_P (type)); + TYPE_DEPENDENT_P_VALID (type) + ? int (TYPE_DEPENDENT_P (type)) : -1); /* Keep the typedef name. */ if (TYPE_NAME (t) != TYPE_NAME (type)) @@ -3974,6 +3984,17 @@ cp_tree_equal (tree t1, tree t2) return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2)) && cp_tree_equal (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2)); + case NON_LVALUE_EXPR: + case VIEW_CONVERT_EXPR: + /* Used for location wrappers with possibly NULL types. */ + if (!TREE_TYPE (t1) || !TREE_TYPE (t2)) + { + if (TREE_TYPE (t1) || TREE_TYPE (t2)) + return false; + break; + } + /* FALLTHROUGH */ + case CAST_EXPR: case STATIC_CAST_EXPR: case REINTERPRET_CAST_EXPR: @@ -3981,10 +4002,8 @@ cp_tree_equal (tree t1, tree t2) case DYNAMIC_CAST_EXPR: case IMPLICIT_CONV_EXPR: case NEW_EXPR: - CASE_CONVERT: - case NON_LVALUE_EXPR: - case VIEW_CONVERT_EXPR: case BIT_CAST_EXPR: + CASE_CONVERT: if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) return false; /* Now compare operands as usual. */ @@ -5132,16 +5151,26 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, if (TYPE_P (*tp)) { - /* Walk into template args without looking through typedefs. */ - if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (*tp)) - WALK_SUBTREE (TI_ARGS (ti)); - /* Don't look through typedefs; walk_tree_fns that want to look through - typedefs (like min_vis_r) need to do that themselves. */ - if (typedef_variant_p (*tp)) + /* If *WALK_SUBTREES_P is 1, we're interested in the syntactic form of + the argument, so don't look through typedefs, but do walk into + template arguments for alias templates (and non-typedefed classes). + + If *WALK_SUBTREES_P > 1, we're interested in type identity or + equivalence, so look through typedefs, ignoring template arguments for + alias templates, and walk into template args of classes. + + See find_abi_tags_r for an example of setting *WALK_SUBTREES_P to 2 + when that's the behavior the walk_tree_fn wants. */ + if (*walk_subtrees_p == 1 && typedef_variant_p (*tp)) { + if (tree ti = TYPE_ALIAS_TEMPLATE_INFO (*tp)) + WALK_SUBTREE (TI_ARGS (ti)); *walk_subtrees_p = 0; return NULL_TREE; } + + if (tree ti = TYPE_TEMPLATE_INFO (*tp)) + WALK_SUBTREE (TI_ARGS (ti)); } /* Not one of the easy cases. We must explicitly go through the @@ -5149,12 +5178,15 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, result = NULL_TREE; switch (code) { + case TEMPLATE_TYPE_PARM: + if (template_placeholder_p (*tp)) + WALK_SUBTREE (CLASS_PLACEHOLDER_TEMPLATE (*tp)); + /* Fall through. */ case DEFERRED_PARSE: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: case UNBOUND_CLASS_TEMPLATE: case TEMPLATE_PARM_INDEX: - case TEMPLATE_TYPE_PARM: case TYPEOF_TYPE: case UNDERLYING_TYPE: /* None of these have subtrees other than those already walked @@ -5912,6 +5944,15 @@ maybe_warn_zero_as_null_pointer_constant (tree expr, location_t loc) return false; } +/* Release memory we no longer need after parsing. */ +void +cp_tree_c_finish_parsing () +{ + if (previous_class_level) + invalidate_class_lookup_cache (); + deleted_copy_types = NULL; +} + #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) /* Complain that some language-specific thing hanging off a tree node has been accessed improperly. */ diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h index 4ad0d82..5551e8f 100644 --- a/gcc/cp/type-utils.h +++ b/gcc/cp/type-utils.h @@ -1,5 +1,5 @@ /* Utilities for querying and manipulating type trees. - Copyright (C) 2013-2020 Free Software Foundation, Inc. + Copyright (C) 2013-2021 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4d499af..a87d5e5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1,5 +1,5 @@ /* Build expressions with type checking for C++ compiler. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -154,6 +154,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain) { if (complain & tf_error) cxx_incomplete_type_diagnostic (value, type, DK_ERROR); + note_failed_type_completion_for_satisfaction (type); return NULL_TREE; } else @@ -1250,6 +1251,8 @@ structural_comptypes (tree t1, tree t2, int strict) /* Both should be types that are not obviously the same. */ gcc_checking_assert (t1 != t2 && TYPE_P (t1) && TYPE_P (t2)); + /* Suppress typename resolution under spec_hasher::equal in place of calling + push_to_top_level there. */ if (!comparing_specializations) { /* TYPENAME_TYPEs should be resolved if the qualifying scope is the @@ -1482,7 +1485,7 @@ structural_comptypes (tree t1, tree t2, int strict) return false; check_alias: - if (comparing_specializations) + if (comparing_dependent_aliases) { /* Don't treat an alias template specialization with dependent arguments as equivalent to its underlying type when used as a @@ -1518,11 +1521,6 @@ comptypes (tree t1, tree t2, int strict) if (t1 == error_mark_node || t2 == error_mark_node) return false; - if (strict == COMPARE_STRICT && comparing_specializations - && (t1 != TYPE_CANONICAL (t1) || t2 != TYPE_CANONICAL (t2))) - /* If comparing_specializations, treat dependent aliases as distinct. */ - strict = COMPARE_STRUCTURAL; - if (strict == COMPARE_STRICT) { if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2)) @@ -2979,7 +2977,8 @@ complain_about_unrecognized_member (tree access_path, tree name, TREE_CODE (access_path) == TREE_BINFO ? TREE_TYPE (access_path) : object_type, name, afi.get_diag_decl ()); - complain_about_access (afi.get_decl (), afi.get_diag_decl (), false); + complain_about_access (afi.get_decl (), afi.get_diag_decl (), + afi.get_diag_decl (), false, ak_none); } } else @@ -3324,7 +3323,15 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, { /* Retain the type if we know the operand is a pointer. */ if (TREE_TYPE (expr) && INDIRECT_TYPE_P (TREE_TYPE (expr))) - return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); + { + if (expr == current_class_ptr + || (TREE_CODE (expr) == NOP_EXPR + && TREE_OPERAND (expr, 0) == current_class_ptr + && (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (expr), TREE_TYPE (current_class_ptr))))) + return current_class_ref; + return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); + } if (type_dependent_expression_p (expr)) return build_min_nt_loc (loc, INDIRECT_REF, expr); expr = build_non_dependent_expr (expr); @@ -5984,7 +5991,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype, tree restype = ptrdiff_type_node; tree target_type = TREE_TYPE (ptrtype); - if (!complete_type_or_else (target_type, NULL_TREE)) + if (!complete_type_or_maybe_complain (target_type, NULL_TREE, complain)) return error_mark_node; if (VOID_TYPE_P (target_type)) @@ -8860,7 +8867,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, LOOKUP_ONLYCONVERTING. */ newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL, ICR_INIT, NULL_TREE, 0, - complain); + complain | tf_no_cleanup); else newrhs = convert_for_assignment (olhstype, newrhs, ICR_ASSIGN, NULL_TREE, 0, complain, LOOKUP_IMPLICIT); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 3fd2b17..9ba2897 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1,6 +1,6 @@ /* Report error messages, build initializers, and perform some front-end optimizations for C++ compiler. - Copyright (C) 1987-2020 Free Software Foundation, Inc. + Copyright (C) 1987-2021 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -569,17 +569,30 @@ split_nonconstant_init_1 (tree dest, tree init, bool nested) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); + /* We may need to add a copy constructor call if + the field has [[no_unique_address]]. */ if (unsafe_return_slot_p (sub)) { - /* We may need to add a copy constructor call if - the field has [[no_unique_address]]. */ + /* But not if the initializer is an implicit ctor call + we just built in digest_init. */ + if (TREE_CODE (value) == TARGET_EXPR + && TARGET_EXPR_LIST_INIT_P (value) + && make_safe_copy_elision (sub, value)) + goto build_init; + + tree name = (DECL_FIELD_IS_BASE (field_index) + ? base_ctor_identifier + : complete_ctor_identifier); releasing_vec args = make_tree_vector_single (value); code = build_special_member_call - (sub, complete_ctor_identifier, &args, inner_type, + (sub, name, &args, inner_type, LOOKUP_NORMAL, tf_warning_or_error); } else - code = build2 (INIT_EXPR, inner_type, sub, value); + { + build_init: + 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); @@ -1466,7 +1479,6 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { tree next; - tree type; if (TREE_CODE (field) != FIELD_DECL || (DECL_ARTIFICIAL (field) @@ -1477,10 +1489,10 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, continue; /* If this is a bitfield, first convert to the declared type. */ - type = TREE_TYPE (field); + tree fldtype = TREE_TYPE (field); if (DECL_BIT_FIELD_TYPE (field)) - type = DECL_BIT_FIELD_TYPE (field); - if (type == error_mark_node) + fldtype = DECL_BIT_FIELD_TYPE (field); + if (fldtype == error_mark_node) return PICFLAG_ERRONEOUS; next = NULL_TREE; @@ -1496,8 +1508,8 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, || identifier_p (ce->index)); if (ce->index == field || ce->index == DECL_NAME (field)) next = ce->value; - else if (ANON_AGGR_TYPE_P (type) - && search_anon_aggr (type, + else if (ANON_AGGR_TYPE_P (fldtype) + && search_anon_aggr (fldtype, TREE_CODE (ce->index) == FIELD_DECL ? DECL_NAME (ce->index) : ce->index)) @@ -1525,7 +1537,7 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, if (ce) { gcc_assert (ce->value); - next = massage_init_elt (type, next, nested, flags, complain); + next = massage_init_elt (fldtype, next, nested, flags, complain); ++idx; } } @@ -1551,25 +1563,24 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, && find_placeholders (next)) CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; } - else if (type_build_ctor_call (TREE_TYPE (field))) + else if (type_build_ctor_call (fldtype)) { /* If this type needs constructors run for default-initialization, we can't rely on the back end to do it for us, so build up TARGET_EXPRs. If the type in question is a class, just build one up; if it's an array, recurse. */ next = build_constructor (init_list_type_node, NULL); - next = massage_init_elt (TREE_TYPE (field), next, nested, flags, - complain); + next = massage_init_elt (fldtype, next, nested, flags, complain); /* Warn when some struct elements are implicitly initialized. */ if ((complain & tf_warning) + && !cp_unevaluated_operand && !EMPTY_CONSTRUCTOR_P (init)) warning (OPT_Wmissing_field_initializers, "missing initializer for member %qD", field); } else { - const_tree fldtype = TREE_TYPE (field); if (TYPE_REF_P (fldtype)) { if (complain & tf_error) @@ -1593,14 +1604,19 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, /* Warn when some struct elements are implicitly initialized to zero. */ if ((complain & tf_warning) + && !cp_unevaluated_operand && !EMPTY_CONSTRUCTOR_P (init)) warning (OPT_Wmissing_field_initializers, "missing initializer for member %qD", field); - if (!zero_init_p (fldtype) - || skipped < 0) - next = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE, - /*static_storage_p=*/false); + if (!zero_init_p (fldtype) || skipped < 0) + { + if (TYPE_REF_P (fldtype)) + next = build_zero_cst (fldtype); + else + next = build_zero_init (fldtype, /*nelts=*/NULL_TREE, + /*static_storage_p=*/false); + } else { /* The default zero-initialization is fine for us; don't @@ -1610,7 +1626,7 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, } } - if (DECL_SIZE (field) && integer_zerop (DECL_SIZE (field)) + if (is_empty_field (field) && !TREE_SIDE_EFFECTS (next)) /* Don't add trivial initialization of an empty base/field to the constructor, as they might not be ordered the way the back-end @@ -1618,7 +1634,7 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, continue; /* If this is a bitfield, now convert to the lowered type. */ - if (type != TREE_TYPE (field)) + if (fldtype != TREE_TYPE (field)) next = cp_convert_and_check (TREE_TYPE (field), next, complain); picflags |= picflag_from_initializer (next); CONSTRUCTOR_APPEND_ELT (v, field, next); diff --git a/gcc/cp/vtable-class-hierarchy.c b/gcc/cp/vtable-class-hierarchy.c index 2a816d8..5cdc175 100644 --- a/gcc/cp/vtable-class-hierarchy.c +++ b/gcc/cp/vtable-class-hierarchy.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012-2020 Free Software Foundation, Inc. +/* Copyright (C) 2012-2021 Free Software Foundation, Inc. This file is part of GCC. |