diff options
Diffstat (limited to 'gcc/cp')
33 files changed, 4720 insertions, 1541 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 44b592b..ff7582d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,1123 @@ +2025-07-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/120471 + * typeck.cc (cp_build_array_ref) <case COND_EXPR>: If idx is not + INTEGER_CST, don't optimize the case (but cp_default_conversion on + array early if it has ARRAY_TYPE) or use + SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0> as new op0 depending + on flag_strong_eval_order and whether op1 and op2 are arrays with + invariant address or tree invariant pointers. Formatting fixes. + +2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_out::walking_bit_field_unit): New flag. + (trees_out::trees_out): Initialize it. + (trees_out::core_vals): Set it. + (trees_out::get_merge_kind): Use it, move previous ad-hoc check + into assertion. + +2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120644 + * decl.cc (cp_finish_decl): Also propagate type to partial + templates. + * module.cc (trees_out::decl_value): Add assertion that the + TREE_TYPE of a streamed template decl matches its inner. + (trees_in::is_matching_decl): Clarify function return type + deduction should only occur for non-TEMPLATE_DECL. + * pt.cc (template_for_substitution): Handle partial specs. + +2025-06-27 Marek Polacek <polacek@redhat.com> + + PR c++/120756 + * pt.cc (resolve_nondeduced_context): Pass complain to mark_used. + +2025-06-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/120777 + * constexpr.cc: Implement C++26 P3533R2 - constexpr virtual + inheritance. + (is_valid_constexpr_fn): Don't reject constexpr cdtors in classes + with virtual bases for C++26, adjust error wording. + (cxx_bind_parameters_in_call): Add ORIG_FUN argument, add + values for __in_chrg and __vtt_parm arguments when needed. + (cxx_eval_dynamic_cast_fn): Adjust function comment, HINT -1 + should be possible. For C++26 if obj is cast from POINTER_PLUS_EXPR, + attempt to use cxx_fold_indirect_ref to simplify it and if successful, + build ADDR_EXPR of that. + (cxx_eval_call_expression): Add orig_fun variable, set it to + fun before looking through clones, pass it to + cxx_bind_parameters_in_call. + (reduced_constant_expression_p): Add SZ argument, pass DECL_SIZE + of FIELD_DECL e.index to recursive calls and don't return false + if SZ is non-NULL and there are unfilled fields with bit position + at or above SZ. + (cxx_fold_indirect_ref_1): Handle reading of vtables using + ptrdiff_t dynamic type instead of some pointer type. Set el_sz + to DECL_SIZE_UNIT value rather than TYPE_SIZE_UNIT of + DECL_FIELD_IS_BASE fields in classes with virtual bases. + (cxx_fold_indirect_ref): In canonicalize_obj_off lambda look + through COMPONENT_REFs with DECL_FIELD_IS_BASE in classes with + virtual bases and adjust off correspondingly. Remove assertion that + off is integer_zerop, pass tree_to_uhwi (off) instead of 0 to the + cxx_fold_indirect_ref_1 call. + * cp-tree.h (publicly_virtually_derived_p): Declare. + (reduced_constant_expression_p): Add another tree argument defaulted + to NULL_TREE. + * method.cc (synthesized_method_walk): Don't clear *constexpr_p + if there are virtual bases for C++26. + * class.cc (build_base_path): Compute fixed_type_p and + virtual_access before checks for build_simple_base_path instead of + after that and conditional cp_build_addr_expr. Use build_simple_path + if !virtual_access even when v_binfo is non-NULL. + (layout_virtual_bases): For build_base_field calls use + access_public_node rather than access_private_node if + publicly_virtually_derived_p. + (build_vtbl_initializer): Revert 2018-09-18 and 2018-12-11 changes. + (publicly_virtually_derived_p): New function. + +2025-06-27 Jason Merrill <jason@redhat.com> + + * class.cc (fixed_type_or_null): Handle class-type CALL_EXPR. + * parser.cc (cp_parser_binary_expression): Fix decltype_p handling. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/98735 + PR c++/118904 + * cp-gimplify.cc (source_location_id): Remove. + (fold_builtin_source_location): Use generate_internal_label. + * module.cc (enum tree_tag): Add 'tt_internal_id' enumerator. + (trees_out::tree_value): Adjust assertion, write definitions + of uncontexted VAR_DECLs. + (trees_in::tree_value): Read variable definitions. + (trees_out::tree_node): Write internal labels, adjust assert. + (trees_in::tree_node): Read internal labels. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120040 + * constexpr.cc (cxx_eval_constant_expression): Handle TYPE_NAME + now being a TYPE_DECL rather than just an IDENTIFIER_NODE. + * init.cc (build_new_constexpr_heap_type): Build a TYPE_DECL for + the returned type; mark the type as artificial. + * module.cc (trees_out::type_node): Add some assertions. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/98735 + PR c++/120040 + * module.cc (trees_out::tree_value): Write TYPE_DECLs. + (trees_in::tree_value): Read TYPE_DECLs. + (trees_out::tree_node): Support uncontexted TYPE_DECLs, and + ensure that all parts of a by-value decl are marked for + streaming. + (trees_out::get_merge_kind): Treat members of uncontexted types + as always unique. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + * decl.cc (grokfndecl): Add explanation of how to attach to + global module. + +2025-06-26 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cxx_initialize_diagnostics): Use + diagnostic_context::set_adjust_diagnostic_info_callback. + +2025-06-26 Jakub Jelinek <jakub@redhat.com> + + * cp-trait.def: Implement C++26 P2830R10 - Constexpr Type Ordering. + (TYPE_ORDER): New. + * method.cc (type_order_value): Define. + * cp-tree.h (type_order_value): Declare. + * semantics.cc (trait_expr_value): Use gcc_unreachable also + for CPTK_TYPE_ORDER, adjust comment. + (finish_trait_expr): Handle CPTK_TYPE_ORDER. + * constraint.cc (diagnose_trait_expr): Likewise. + +2025-06-25 Martin Jambor <mjambor@suse.cz> + + * coroutines.h (class cp_coroutine_transform): Remove member + orig_fn_body. + +2025-06-24 Jakub Jelinek <jakub@redhat.com> + + PR c++/120773 + * decl.cc (grokfndecl): Implement C++26 P3618R0 - Allow attaching + main to the global module. Only pedwarn for current_lang_name + other than lang_name_cplusplus and adjust pedwarn wording. + +2025-06-23 Tobias Burnus <tburnus@baylibre.com> + + * parser.cc (OACC_WAIT_CLAUSE_MASK): Ass if clause. + +2025-06-18 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/115908 + PR c++/118074 + PR c++/95615 + * coroutines.cc (coro_frame_refcount_id): New. + (coro_init_identifiers): Initialise coro_frame_refcount_id. + (build_actor_fn): Set up initial_await_resume_called. Handle + decrementing of the frame reference count. Return directly to + the caller if that is non-zero. + (cp_coroutine_transform::wrap_original_function_body): Use a + conditional eh-only cleanup around the initial await expression + to release the body use on exception before initial await + resume. + (cp_coroutine_transform::build_ramp_function): Wrap the called + body in a cleanup that releases a use of the frame when we + return to the ramp. Implement frame, promise and argument copy + destruction via conditional cleanups when the frame use count + is zero. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (struct coroutine_info): Update comments. + (struct coro_aw_data): Remove self_handle and add in + information to create the handle in lowering. + (expand_one_await_expression): Build a temporary coroutine + handle. + (build_actor_fn): Remove reference to the frame copy of the + coroutine handle. + (cp_coroutine_transform::wrap_original_function_body): Remove + reference to the frame copy of the coroutine handle. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_expression_awaits): Elide assume + attributes containing await expressions, since these have + side effects. Emit a diagnostic that this has been done. + +2025-06-17 Jason Merrill <jason@redhat.com> + + PR c++/120678 + * cp-trait.def (IS_TRIVIALLY_DESTRUCTIBLE): Fix nargs. + +2025-06-17 Jason Merrill <jason@redhat.com> + + * module.cc (module_state::write_diagnostic_classification): New. + (module_state::write_begin): Call it. + (module_state::read_diagnostic_classification): New. + (module_state::read_initial): Call it. + (dk_string, dump_dc_change): New. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (finish_co_await_expr): Do not allow in an + unevaluated context. + (finish_co_yield_expr): Likewise. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120273 + * coroutines.cc + (cp_coroutine_transform::wrap_original_function_body): Use + function start and end locations when synthesizing code. + (cp_coroutine_transform::cp_coroutine_transform): Set the + function end location. + +2025-06-16 Jason Merrill <jason@redhat.com> + + * constraint.cc (failed_completions_map): New. + (note_failed_type_completion): Rename from + note_failed_type_completion_for_satisfaction. Add + -Wsfinae-incomplete handling. + (failed_completion_location): New. + * class.cc (finish_struct_1): Add -Wsfinae-incomplete warning. + * decl.cc (require_deduced_type): Adjust. + (finish_function): Add -Wsfinae-incomplete warning. + * typeck.cc (complete_type_or_maybe_complain): Adjust. + (cxx_sizeof_or_alignof_type): Call note_failed_type_completion. + * pt.cc (dependent_template_arg_p): No longer static. + * cp-tree.h: Adjust. + +2025-06-16 yxj-github-437 <2457369732@qq.com> + + * parser.cc (cp_parser_asm_operand_list): Check for unexpanded + parameter packs. + +2025-06-14 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_co_await): Identify diagnostics + for initial and final await expressions. + (cp_coroutine_transform::wrap_original_function_body): Do + not handle initial and final await expressions here ... + (cp_coroutine_transform::apply_transforms): ... handle them + here and avoid duplicate diagnostics. + * coroutines.h: Declare inital and final await expressions + in the transform class. Save the function closing brace + location. + +2025-06-13 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/116775 + * coroutines.cc (analyze_expression_awaits): When we see + a builtin_constant_p call, and that contains one or more + await expressions, then replace the call with its result + and discard the unevaluated operand. + +2025-06-13 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Set can_throw. + +2025-06-12 Alfie Richards <alfie.richards@arm.com> + + * decl.cc (maybe_version_functions): Change record_function_versions + call to add_function_version. + +2025-06-12 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (union lang_type::maybe_objc_info): New type. + (struct lang_type): Use union maybe_objc_info info member + instead of tree objc_info. + * lex.cc (copy_lang_type): Use sizeof (struct lang_type) + just for ObjC++ and otherwise offsetof (struct lang_type, info). + (maybe_add_lang_type_raw): Likewise. + (cxx_make_type): Formatting fix. + +2025-06-09 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120495 + PR c++/115605 + * pt.cc (lookup_template_class): Honour provided namespace contexts + when looking up class templates. + +2025-06-06 Jason Merrill <jason@redhat.com> + + PR c++/120555 + * decl2.cc (fn_being_defined, fn_template_being_defined): New. + (mark_used): Check fn_template_being_defined. + +2025-06-05 Patrick Palka <ppalka@redhat.com> + + PR c++/120224 + * pt.cc (tsubst_function_decl): Return error_mark_node if + substituting into the formal parameter list failed. + (tsubst_decl) <case PARM_DECL>: Return error_mark_node + upon TREE_TYPE substitution failure, when in a SFINAE + context. Return error_mark_node upon DECL_CHAIN substitution + failure. + +2025-06-05 Patrick Palka <ppalka@redhat.com> + + PR c++/118340 + * constexpr.cc (maybe_constant_value): First try looking up each + operand in the cv_cache and reusing the result. + +2025-06-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_fn_parms): Move from free function.. + (cp_coroutine_transform::analyze_fn_parms):... to method. + (cp_coroutine_transform::apply_transforms): Adjust call to + analyze_fn_parms. + * coroutines.h: Declare analyze_fn_parms. + +2025-06-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (expand_one_await_expression): Set the + initial_await_resume_called flag here. + (build_actor_fn): Populate the frame accessor for the + initial_await_resume_called flag. + (cp_coroutine_transform::wrap_original_function_body): Do + not modify the initial_await expression to include the + initial_await_resume_called flag here. + +2025-06-04 Jason Merrill <jason@redhat.com> + + PR c++/120502 + * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation + before genericize. + * constexpr.cc (cxx_eval_store_expression): Add comment. + +2025-06-03 Jason Merrill <jason@redhat.com> + + * name-lookup.h (operator|, operator|=): Define for WMB_Flags. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Fix refs and arrays of unknown + bound. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/120506 + * constexpr.cc (cxx_eval_outermost_constant_expr): Always check + CONSTRUCTOR_NO_CLEARING. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Remove an unused + label, guard the frame deallocation correctly, use + simpler APIs to build if and return statements. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/118903 + * constexpr.cc (potential_constant_expression_1): Emit + an error when co_await et. al. are used in constexpr + contexts. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * error.cc (dump_expr): Add co_await, co_yield and co_return. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Handle non-classes. + (constructible_expr): Check for abstract class here... + (is_xible_helper): ...not here. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]: + Add cp_unevaluated. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * cp-tree.h (maybe_convert_cond): Declare. + * parser.cc (cp_parser_omp_context_selector): Call + maybe_convert_cond and fold_build_cleanup_point_expr on the + expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + * pt.cc (tsubst_omp_context_selector): Likewise. + * semantics.cc (maybe_convert_cond): Remove static declaration. + +2025-05-30 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (lambda_capture_field_type): Handle 'this' normally. + (build_capture_proxy): Special-case 'this' by-ref capture more. + (nonlambda_method_basetype): Look through xobj lambdas. + +2025-05-30 Julian Brown <julian@codesourcery.com> + Tobias Burnus <tburnus@baylibre.com> + + * constexpr.cc (reduced_constant_expression_p): Add OMP_DECLARE_MAPPER + case. + (cxx_eval_constant_expression, potential_constant_expression_1): + Likewise. + * cp-gimplify.cc (cxx_omp_finish_mapper_clauses): New function. + * cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES, + LANG_HOOKS_OMP_MAPPER_LOOKUP, LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE, + LANG_HOOKS_OMP_MAP_ARRAY_SECTION): Define langhooks. + * cp-tree.h (lang_decl_base): Add omp_declare_mapper_p field. Recount + spare bits comment. + (DECL_OMP_DECLARE_MAPPER_P): New macro. + (omp_mapper_id): Add prototype. + (cp_check_omp_declare_mapper): Add prototype. + (omp_instantiate_mappers): Add prototype. + (cxx_omp_finish_mapper_clauses): Add prototype. + (cxx_omp_mapper_lookup): Add prototype. + (cxx_omp_extract_mapper_directive): Add prototype. + (cxx_omp_map_array_section): Add prototype. + * decl.cc (check_initializer): Add OpenMP declare mapper support. + (cp_finish_decl): Set DECL_INITIAL for OpenMP declare mapper var decls + as appropriate. + * decl2.cc (mark_used): Instantiate OpenMP "declare mapper" magic var + decls. + * error.cc (dump_omp_declare_mapper): New function. + (dump_simple_decl): Use above. + * parser.cc (cp_parser_omp_clause_map): Add KIND parameter. Support + "mapper" modifier. + (cp_parser_omp_all_clauses): Add KIND argument to + cp_parser_omp_clause_map call. + (cp_parser_omp_target): Call omp_instantiate_mappers before + finish_omp_clauses. + (cp_parser_omp_declare_mapper): New function. + (cp_parser_omp_declare): Add "declare mapper" support. + * pt.cc (tsubst_decl): Adjust name of "declare mapper" magic var decls + once we know their type. + (tsubst_omp_clauses): Call omp_instantiate_mappers before + finish_omp_clauses, for target regions. + (tsubst_expr): Support OMP_DECLARE_MAPPER nodes. + (instantiate_decl): Instantiate initialiser (i.e definition) for OpenMP + declare mappers. + * semantics.cc (gimplify.h): Include. + (omp_mapper_id, omp_mapper_lookup, omp_extract_mapper_directive, + cxx_omp_map_array_section, cp_check_omp_declare_mapper): New functions. + (finish_omp_clauses): Delete GOMP_MAP_PUSH_MAPPER_NAME and + GOMP_MAP_POP_MAPPER_NAME artificial clauses. + (omp_target_walk_data): Add MAPPERS field. + (finish_omp_target_clauses_r): Scan for uses of struct/union/class type + variables. + (finish_omp_target_clauses): Create artificial mapper binding clauses + for used structs/unions/classes in offload region. + +2025-05-29 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cxx_format_postprocessor::clone): Update to use + unique_ptr. + (cxx_dump_pretty_printer::cxx_dump_pretty_printer): Likewise. + (cxx_initialize_diagnostics): Likewise. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (build_capture_proxy): Check pointerness of the + member, not the proxy type. + (lambda_expr_this_capture): Don't assume current_class_ref. + (nonlambda_method_basetype): Likewise. + * semantics.cc (finish_non_static_data_member): Don't assume + TREE_TYPE (object) is set. + (finish_this_expr): Check current_class_type for lambda, + not current_class_ref. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/109283 + * coroutines.cc (find_any_await): Only save the statement + pointer if the caller passes a place for it. + (flatten_await_stmt): When checking that ternary expressions + have been handled, also check that they contain a co_await. + +2025-05-29 Jason Merrill <jason@redhat.com> + + * decl.cc (start_decl): Also set invalid_constexpr + for maybe_constexpr_fn. + * parser.cc (cp_parser_jump_statement): Likewise. + * constexpr.cc (potential_constant_expression_1): Ignore + goto to an artificial label. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + * parser.cc (cp_parser_omp_metadirective): Do not call + cp_parser_skip_to_end_of_block_or_statement after an error. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + PR c/120180 + * parser.cc (cp_parser_omp_metadirective): Only consume the + token if it is the expected close paren. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_fn_parms): No longer + create a parameter copy guard var. + * coroutines.h (struct param_info): Remove the + entry for the parameter copy destructor guard. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120453 + * cp-tree.h (DECL_RAMP_P): New. + * typeck.cc (check_return_expr): Use DECL_RAMP_P instead + of DECL_RAMP_FN. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * cp-trait.def (IS_DESTRUCTIBLE, IS_NOTHROW_DESTRUCTIBLE) + (IS_TRIVIALLY_DESTRUCTIBLE): New. + * constraint.cc (diagnose_trait_expr): Explain them. + * method.cc (destructible_expr): New. + (is_xible_helper): Use it. + * semantics.cc (finish_trait_expr): Handle new traits. + (trait_expr_value): Likewise. Complain about asking + whether a deleted dtor is trivial. + +2025-05-28 Jason Merrill <jason@redhat.com> + + * module.cc (module_state::write_namespaces): Write + using-directives. + (module_state::read_namespaces): And read them. + * name-lookup.cc (add_using_namespace): Add overload. Build a + USING_DECL for modules. + (name_lookup::search_usings, name_lookup::queue_usings) + (using_directives_contain_std_p): Strip the USING_DECL. + * name-lookup.h: Declare it. + * parser.cc (cp_parser_import_declaration): Set MK_EXPORTING + for export import. + +2025-05-27 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (cp_coroutine_transform::build_ramp_function): + Replace TRUTH_AND_EXPR with TRUTH_ANDIF_EXPR in three places. + +2025-05-26 Tobias Burnus <tburnus@baylibre.com> + + PR c++/120413 + * semantics.cc (finish_omp_target_clauses_r): Handle + BIND_EXPR with empty BIND_EXPR_BLOCK. + +2025-05-26 Jason Merrill <jason@redhat.com> + + * cp-tree.h: Declare tinst_dump_id. + * cp-objcp-common.cc (cp_register_dumps): Set it. + * pt.cc (push_tinst_level_loc): Dump it. + (reopen_tinst_level): Here too. + (tinst_complete_p): New. + (instantiate_pending_templates): Don't reopen_tinst_level for + already-complete instantiations. + +2025-05-26 Jason Merrill <jason@redhat.com> + + * cp-tree.h (class cxx_dump_pretty_printer): New. + * error.cc (cxx_dump_pretty_printer): Ctor/dtor definitions. + +2025-05-25 Jason Merrill <jason@redhat.com> + + * error.cc (dump_template_bindings): Correct skipping of + redundant bindings. + +2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120363 + * decl2.cc (get_tls_init_fn): Set context as global_namespace. + (get_tls_wrapper_fn): Likewise. + +2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120414 + * module.cc (trees_in::tree_node): Allow reading a USING_DECL + when streaming tt_data_member. + +2025-05-23 Jason Merrill <jason@redhat.com> + + * mangle.cc (mangle_decl_string): Don't push_tinst_level. + +2025-05-22 Jason Merrill <jason@redhat.com> + + PR c++/120935 + * cp-gimplify.cc (cp_fold): Check always_inline. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Replace ramp + cleanup try-catch block with eh-only cleanup statements. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Use + decltype(auto) to determine the type of the temporary + get_return_object. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/119916 + * coroutines.cc + (cp_coroutine_transform::wrap_original_function_body): Do not + initialise initial_await_resume_called here... + (cp_coroutine_transform::build_ramp_function): ... but here. + When the coroutine is not void, initialize a GRO object from + promise.get_return_object(). Use this as the argument to the + return expression. Use a regular cleanup for the GRO, since + it is ramp-local. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120349 + * module.cc (trees_out::core_bools): Always mark vtables as + DECL_EXTERNAL. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120013 + * module.cc (trees_in::install_entity): Handle re-registering + the inner TYPE_DECL of a partial specialisation. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120350 + * rtti.cc (get_tinfo_decl_direct): Mark TREE_ADDRESSABLE. + +2025-05-16 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Do the conversion unconditionally, even for same-type cases. + +2025-05-16 Iain Sandoe <iain@sandoe.co.uk> + + * typeck.cc (check_return_expr): Suppress conversions for NVRO + in coroutine ramp functions. + +2025-05-16 Iain Sandoe <iain@sandoe.co.uk> + + * decl.cc (poplevel): Set BLOCK_OUTER_CURLY_BRACE_P on the + body block for functions with no subblocks. + +2025-05-16 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (importer_interface): Adjust flags. + (get_importer_interface): Rename flags. + (trees_out::core_bools): Clean up special casing. + (trees_out::write_function_def): Rename flag. + +2025-05-15 Patrick Palka <ppalka@redhat.com> + + PR c++/120161 + * pt.cc (unify) <case RECORD_TYPE>: When comparing specializations + of a non-primary template, still perform a type comparison. + +2025-05-15 Jason Merrill <jason@redhat.com> + + * module.cc (trees_out::lang_decl_bools): Stream implicit_constexpr. + (trees_in::lang_decl_bools): Likewise. + (trees_in::is_matching_decl): Check it. + +2025-05-15 Jason Merrill <jason@redhat.com> + + PR c++/99599 + * pt.cc (conversion_may_instantiate_p): Make sure + classes are complete. + +2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Remove a remnant comment. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120125 + * module.cc (trees_out::write_function_def): Only set + DECL_NOT_REALLY_EXTERN if the importer might need to emit it. + * optimize.cc (maybe_thunk_body): Don't assume 'fn' has a cgraph + node created. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119864 + * decl2.cc (start_objects): Only use module initialized for + host. + (c_parse_final_cleanups): Don't always create an OMP offload + init function in modules. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + * name-lookup.cc (lookup_imported_hidden_friend): Add back + lazy_load_pendings with comment. + +2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Add to_underlying. + +2025-05-14 Owen Avery <powerboat9.gamer@gmail.com> + Jason Merrill <jason@redhat.com> + + * method.cc (synthesized_method_walk): Check whether + -Wvirtual-move-assign is enabled at the location of a base + class's move assignment operator. + +2025-05-12 Jason Merrill <jason@redhat.com> + + PR c++/120012 + * class.cc (check_non_pod_aggregate): Check is_empty_class. + +2025-05-10 Jason Merrill <jason@redhat.com> + + PR c++/120204 + * pt.cc (tsubst_baselink): Always error if lookup fails. + +2025-05-09 Jason Merrill <jason@redhat.com> + + * decl2.cc (determine_visibility): Ignore args for friend templates. + +2025-05-09 Jason Merrill <jason@redhat.com> + + PR c++/99599 + PR c++/120185 + * class.cc (type_has_converting_constructor): Handle null parm. + * pt.cc (fn_type_unification): Skip early non-dep checking if + no concepts. + +2025-05-08 Jason Merrill <jason@redhat.com> + + PR c++/99599 + * cp-tree.h (type_has_converting_constructor): Declare. + * class.cc (type_has_converting_constructor): New. + * pt.cc (conversion_may_instantiate_p): Don't check completeness. + +2025-05-05 Simon Martin <simon@nasilyan.com> + + * cp-tree.h (parsing_default_capturing_generic_lambda_in_template): + Remove obsolete prototype. + +2025-05-02 Jason Merrill <jason@redhat.com> + + PR c++/115207 + * decl.cc (cp_finish_decl): Call layout_decl after CTAD. + +2025-05-02 Jason Merrill <jason@redhat.com> + + PR c++/120012 + * cp-tree.h (struct lang_type): Add non_aggregate_pod. + (CLASSTYPE_NON_AGGREGATE_POD): New. + * class.cc (check_bases_and_members): Set it. + (check_non_pod_aggregate): Diagnose it. + +2025-05-02 Jakub Jelinek <jakub@redhat.com> + + PR c++/117827 + * init.cc (build_vec_init): Push to *cleanup_flags clearing of rval + instead of setting of iterator to maxindex. + +2025-05-01 Patrick Palka <ppalka@redhat.com> + + * constexpr.cc (explain_invalid_constexpr_fn): In the + DECL_CONSTRUCTOR_P branch pass the non-genericized body to + require_potential_constant_expression. + +2025-05-01 Patrick Palka <ppalka@redhat.com> + + PR c++/119034 + PR c++/68942 + * pt.cc (tsubst_expr) <case CALL_EXPR>: Revert PR68942 fix. + * semantics.cc (finish_call_expr): Ensure the callee of an + ADL-enabled call is wrapped in an OVERLOAD. + +2025-05-01 Jason Merrill <jason@redhat.com> + + * Make-lang.in: Don't pass the full path to gperf. + * std-name-hint.h: Regenerate. + +2025-05-01 Jason Merrill <jason@redhat.com> + + PR c++/119162 + * constexpr.cc (find_deleted_heap_var): Remove. + (cxx_eval_call_expression): Don't call it. Don't set TREE_STATIC on + heap vars. + (cxx_eval_outermost_constant_expr): Don't mess with varpool. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120023 + * module.cc (depset::hash::find_dependencies): Also call + add_deduction_guides when walking one. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119938 + * pt.cc (get_template_parm_object): When !check_init, add assert + that expr really is constant and mark decl as such. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119551 + PR c++/119996 + * module.cc (depset::hash::make_dependency): Also mark inline + variables referencing TU-local values as exposures here. + (depset::hash::finalize_dependencies): Add error message for + inline variables. + +2025-04-30 Patrick Palka <ppalka@redhat.com> + + PR c++/119981 + PR c++/119378 + * pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Substitute + into template parameter list first. When substituting the + context, only set processing_template_decl if there's more + than one level of introduced template parameters. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * parser.cc: Include "analyzer/analyzer-language.h". + (ana::cp_translation_unit): New class. + (cp_parser_translation_unit): Add call to + ana::on_finish_translation_unit. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * cxx-pretty-print.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * error.cc: Likewise. + * name-lookup.cc: Likewise. + * parser.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * name-lookup.cc: Include "make-unique.h". + (namespace_hints::convert_candidates_to_name_hint): Use + ::make_unique rather than "new" when making + show_candidate_location and suggest_alternatives. + (namespace_hints::maybe_decorate_with_limit): Likewise when making + namespace_limit_reached. + (suggest_alternatives_for_1): Likewise when making + suggest_missing_option. + (maybe_suggest_missing_std_header): Likewise when making + missing_std_header. + (macro_use_before_def::maybe_make): Use std::unique_ptr. + (macro_use_before_def::macro_use_before_def): Make public. + (lookup_name_fuzzy): Use ::make_unique rather than "new" when + making suggest_missing_header. + * parser.cc: Include "make-unique.h". + (cp_parser_error_1): Use ::make_unique rather than "new" when + making suggest_missing_header. + +2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119939 + * module.cc (trees_out::lang_decl_vals): Also stream + lang->u.fn.context when DECL_UNIQUE_FRIEND_P. + (trees_in::lang_decl_vals): Likewise. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * call.cc (type_passed_as): Remove the + targetm.calls.promote_prototypes call. + (convert_for_arg_passing): Likewise. + * typeck.cc (cxx_safe_arg_type_equiv_p): Likewise. + +2025-04-25 Jason Merrill <jason@redhat.com> + + PR c++/119764 + PR c++/87185 + * lambda.cc (insert_capture_proxy): Handle noexcept lambda. + (prune_lambda_captures): Likewise, in ABI v21. + +2025-04-25 Jason Merrill <jason@redhat.com> + + * cp-tree.h (struct tinst_level): Add had_errors bit. + * pt.cc (push_tinst_level_loc): Clear it. + (pop_tinst_level): Set it. + (reopen_tinst_level): Check it. + (instantiate_pending_templates): Call limit_bad_template_recursion. + +2025-04-24 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Return early if + not enabled. + +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + * name-lookup.cc (lookup_imported_hidden_friend): Remove + unnecessary lazy_load_pendings. + +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119863 + * name-lookup.cc (get_mergeable_namespace_binding): Remove + no-longer-used function. + (lookup_imported_hidden_friend): Also look for hidden imported + decls in an attached decl's module. + +2025-04-21 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Move + verify_constant later. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/118775 + * constexpr.cc (cxx_eval_call_expression): Add assert. + (fold_to_constant): Handle processing_template_decl. + * init.cc (build_new_1): Use fold_to_constant. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/99456 + * constexpr.cc (cxx_eval_constant_expression): Check strict + instead of manifestly_const_eval. + (maybe_constant_init_1): Be strict for static constexpr vars. + +2025-04-19 Jason Merrill <jason@redhat.com> + + * coroutines.cc (coro_build_expr_stmt) + (coro_build_cvt_void_expr_stmt): Remove. + (build_actor_fn): Use finish_expr_stmt. + * semantics.cc (finish_expr_stmt): Avoid wrapping statement in + EXPR_STMT. + (finish_stmt_expr_expr): Add comment. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (is_valid_constexpr_fn): Improve diagnostic. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Give both + expression and allocation location in allocated storage diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * name-lookup.cc (name_lookup::preserve_state): Fix reserve call. + * rtti.cc (get_tinfo_desc): Use vec_safe_grow_cleared. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * semantics.cc (finish_type_pack_element): Add more info + to diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * decl.cc (cp_make_fname_decl): Prevent silent failure. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * lex.cc (unqualified_name_lookup_error): Handle 'requires' better. + +2025-04-17 Jason Merrill <jason@redhat.com> + + PR c++/113360 + * cp-tree.h (struct language_function): Add erroneous bit. + * constexpr.cc (explain_invalid_constexpr_fn): Return if set. + (cxx_eval_call_expression): Quiet if set. + * parser.cc (cp_parser_function_definition_after_declarator) + * pt.cc (instantiate_body): Set it. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/114772 + PR c++/101180 + * pt.cc (apply_late_template_attributes): Also override + target_option_current_node. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Preserve flags + on the attribute list. + +2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119755 + * lambda.cc (prune_lambda_captures): Remove pruned capture from + function's BLOCK_VARS and BIND_EXPR_VARS. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/111075 + * constexpr.cc (cxx_eval_call_expression): Allow trivial + call from a thunk. + +2025-04-15 Patrick Palka <ppalka@redhat.com> + + PR c++/119807 + PR c++/112288 + * pt.cc (tsubst_friend_function): Skip remapping an + existing specialization if it doesn't match the shape of + the new friend definition. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/113835 + * constexpr.cc (cxx_eval_outermost_constant_expr): Bail out early + for std::vector(N). + +2025-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/99214 + * constraint.cc (satisfy_declaration_constraints): Pass the + original ARGS to push_tinst_level. + +2025-04-13 Patrick Palka <ppalka@redhat.com> + + PR c++/115639 + * constexpr.cc (struct constexpr_call): Add NSDMIs to each + field. Replace 'result' data member with 3-element 'results' + array and a 'result' accessor function. Remove + 'manifestly_const_eval' data member. + (constexpr_call_hasher::equal): Adjust after constexpr_call + layout change. + (cxx_eval_call_expression): Likewise. Define some local + variables closer to their first use. Use unknown_type_node + instead of NULL_TREE as the "in progress" result. After + successully evaluating a call with mce_unknown, also cache the + result in the corresponding mce_true and mce_false slots. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Don't check for + mismatches when importing a DECL_MAYBE_DELETED function over one + that's already finished. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Add custom errors for + different kinds of mismatches. + +2025-04-12 Patrick Palka <ppalka@redhat.com> + + PR c++/116416 + * constexpr.cc (maybe_constant_init_1): Generalize type of + of manifestly_const_eval parameter from bool to mce_value. + (maybe_constant_init): Define 3-parameter version taking a + manifestly_const_eval instead of bool parameter. + (cxx_constant_init): Adjust. + * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false + to maybe_constant_init during prvalue folding if ff_mce_false is + set. + * cp-tree.h (maybe_constant_init): Declare new overload. + +2025-04-11 Jason Merrill <jason@redhat.com> + + PR c++/114970 + * cp-gimplify.cc (cp_build_init_expr_for_ctor): Suppress warnings on + return_this COMPOUND_EXPR. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119345 + * pt.cc (add_extra_args): Also register a specialization + of the captured variable. + +2025-04-10 Patrick Palka <ppalka@redhat.com> + + PR c++/119687 + * pt.cc (alias_ctad_tweaks): Use lkp_range / lkp_iterator + instead of ovl_iterator. + +2025-04-10 Jakub Jelinek <jakub@redhat.com> + + PR translation/119684 + * error.cc (cp_print_error_function): Use G_ instead of _ for + pp_printf arguments. + (function_category): Use G_ instead of _. + (print_instantiation_full_context): Use G_ instead of _ in pp_verbatim + arguments. + (print_location): Likewise. + (print_instantiation_partial_context): Likewise. + (maybe_print_constexpr_context): Likewise. + (print_constrained_decl_info): Use G_() around pp_verbatim argument. + (print_concept_check_info): Likewise. + (print_constraint_context_head): Likewise. + (print_requires_expression_info): Likewise. Merge separate pp_verbatim + "in requirements " and "with " into one with conditional messages. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119175 + * mangle.cc (decl_mangling_context): Look through lambda type. + +2025-04-09 Patrick Palka <ppalka@redhat.com> + + PR c++/119574 + * pt.cc (add_extra_args): Remove checking assert. + +2025-04-09 Jason Merrill <jason@redhat.com> + + PR c++/118698 + * constraint.cc (struct norm_info): Add tf_partial. + * pt.cc (any_template_parm_r): Handle LAMBDA_EXPR_EXTRA_ARGS. + +2025-04-08 Jason Merrill <jason@redhat.com> + + PR c++/117530 + * pt.cc (instantiate_template): Check retrieve_specialization after + tsubst. + +2025-04-07 Jason Merrill <jason@redhat.com> + + PR c++/119652 + * constexpr.cc (cxx_eval_outermost_constant_expr): Also don't add a + TARGET_EXPR around AGGR_INIT_EXPR. + +2025-04-06 Patrick Palka <ppalka@redhat.com> + + PR c++/118626 + * pt.cc (maybe_dependent_member_ref): Restrict TYPENAME_TYPE + shortcut to non-typedef TYPE_DECL. + +2025-04-06 Patrick Palka <ppalka@redhat.com> + + PR c++/118626 + * pt.cc (maybe_dependent_member_ref): Substitute and return the + stripped type if we decided to not rewrite it directly. + 2025-04-05 Patrick Palka <ppalka@redhat.com> PR c++/118249 diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 25143c8..dae3c68 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -168,8 +168,8 @@ $(srcdir)/cp/std-name-hint.h: $(srcdir)/cp/std-name-hint.gperf else $(srcdir)/cp/std-name-hint.h: | $(srcdir)/cp/std-name-hint.gperf endif - gperf -o -C -E -k '1,2,7,11,$$' -D -N find -L C++ \ - $(srcdir)/cp/std-name-hint.gperf --output-file $(srcdir)/cp/std-name-hint.h + cd $(srcdir)/cp; gperf -o -C -E -k '1,2,7,11,$$' -D -N find -L C++ \ + std-name-hint.gperf --output-file std-name-hint.h # The std-name-hint.gperf file itself is generated from a general # C++ API description. diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6caac89..2c3ef3d 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9707,11 +9707,6 @@ type_passed_as (tree type) /* Pass classes with copy ctors by invisible reference. */ if (TREE_ADDRESSABLE (type)) type = build_reference_type (type); - else if (targetm.calls.promote_prototypes (NULL_TREE) - && INTEGRAL_TYPE_P (type) - && COMPLETE_TYPE_P (type) - && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node))) - type = integer_type_node; return type; } @@ -9747,11 +9742,6 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain) /* Pass classes with copy ctors by invisible reference. */ else if (TREE_ADDRESSABLE (type)) val = build1 (ADDR_EXPR, build_reference_type (type), val); - else if (targetm.calls.promote_prototypes (NULL_TREE) - && INTEGRAL_TYPE_P (type) - && COMPLETE_TYPE_P (type) - && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node))) - val = cp_perform_integral_promotions (val, complain); if (complain & tf_warning) maybe_warn_parm_abi (type, cp_expr_loc_or_input_loc (val)); diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 2b694b9..9a41c00 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -347,9 +347,18 @@ build_base_path (enum tree_code code, || processing_template_decl || in_template_context); + fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); + + /* Do we need to look in the vtable for the real offset? */ + virtual_access = (v_binfo && fixed_type_p <= 0); + /* For a non-pointer simple base reference, express it as a COMPONENT_REF without taking its address (and so causing lambda capture, 91933). */ - if (code == PLUS_EXPR && !v_binfo && !want_pointer && !has_empty && !uneval) + if (code == PLUS_EXPR + && !want_pointer + && !has_empty + && !uneval + && !virtual_access) return build_simple_base_path (expr, binfo); if (!want_pointer) @@ -362,7 +371,6 @@ build_base_path (enum tree_code code, expr = mark_rvalue_use (expr); offset = BINFO_OFFSET (binfo); - fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull); target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo); /* TARGET_TYPE has been extracted from BINFO, and, is therefore always cv-unqualified. Extract the cv-qualifiers from EXPR so that the @@ -371,9 +379,6 @@ build_base_path (enum tree_code code, (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr)))); ptr_target_type = build_pointer_type (target_type); - /* Do we need to look in the vtable for the real offset? */ - virtual_access = (v_binfo && fixed_type_p <= 0); - /* Don't bother with the calculations inside sizeof; they'll ICE if the source type is incomplete and the pointer value doesn't matter. In a template (even in instantiate_non_dependent_expr), we don't have vtables @@ -5724,6 +5729,50 @@ type_has_user_provided_constructor (tree t) return false; } +/* Returns true iff class T has a constructor that accepts a single argument + and does not have a single parameter of type reference to T. + + This does not exclude explicit constructors because they are still + considered for conversions within { } even though choosing one is + ill-formed. */ + +bool +type_has_converting_constructor (tree t) +{ + if (!CLASS_TYPE_P (t)) + return false; + + if (!TYPE_HAS_USER_CONSTRUCTOR (t)) + return false; + + for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) + { + tree fn = *iter; + tree parm = FUNCTION_FIRST_USER_PARMTYPE (fn); + if (parm == NULL_TREE) + /* Varargs. */ + return true; + if (parm == void_list_node + || !sufficient_parms_p (TREE_CHAIN (parm))) + /* Can't accept a single argument, so won't be considered for + conversion. */ + continue; + if (TREE_CODE (fn) == TEMPLATE_DECL + || TREE_CHAIN (parm) != void_list_node) + /* Not a simple single parameter. */ + return true; + if (TYPE_MAIN_VARIANT (non_reference (TREE_VALUE (parm))) + != DECL_CONTEXT (fn)) + /* The single parameter has the wrong type. */ + return true; + if (get_constraints (fn)) + /* Constrained. */ + return true; + } + + return false; +} + /* Returns true iff class T has a user-provided or explicit constructor. */ bool @@ -6413,9 +6462,7 @@ check_bases_and_members (tree t) Again, other conditions for being an aggregate are checked elsewhere. */ CLASSTYPE_NON_AGGREGATE (t) - |= ((cxx_dialect < cxx20 - ? type_has_user_provided_or_explicit_constructor (t) - : TYPE_HAS_USER_CONSTRUCTOR (t)) + |= (type_has_user_provided_or_explicit_constructor (t) || TYPE_POLYMORPHIC_P (t)); /* This is the C++98/03 definition of POD; it changed in C++0x, but we retain the old definition internally for ABI reasons. */ @@ -6437,6 +6484,20 @@ check_bases_and_members (tree t) CLASSTYPE_NON_LAYOUT_POD_P (t) = true; } + /* P1008: Prohibit aggregates with user-declared constructors. */ + if (cxx_dialect >= cxx20 && TYPE_HAS_USER_CONSTRUCTOR (t)) + { + CLASSTYPE_NON_AGGREGATE (t) = true; + if (!CLASSTYPE_NON_LAYOUT_POD_P (t)) + { + /* c++/120012: The C++20 aggregate change affected layout. */ + if (!abi_version_at_least (21)) + CLASSTYPE_NON_LAYOUT_POD_P (t) = true; + if (abi_version_crosses (21)) + CLASSTYPE_NON_AGGREGATE_POD (t) = true; + } + } + /* If the only explicitly declared default constructor is user-provided, set TYPE_HAS_COMPLEX_DFLT. */ if (!TYPE_HAS_COMPLEX_DFLT (t) @@ -6698,9 +6759,11 @@ layout_virtual_bases (record_layout_info rli, splay_tree offsets) { /* This virtual base is not a primary base of any class in the hierarchy, so we have to add space for it. */ - next_field = build_base_field (rli, vbase, - access_private_node, - offsets, next_field); + tree access = access_private_node; + if (publicly_virtually_derived_p (BINFO_TYPE (vbase), t)) + access = access_public_node; + next_field = build_base_field (rli, vbase, access, offsets, + next_field); } } } @@ -6809,7 +6872,8 @@ end_of_class (tree t, eoc_mode mode) static void check_non_pod_aggregate (tree field) { - if (!abi_version_crosses (17) || cxx_dialect < cxx14) + if ((!abi_version_crosses (17) || cxx_dialect < cxx14) + && (!abi_version_crosses (21) || cxx_dialect < cxx20)) return; if (TREE_CODE (field) != FIELD_DECL || (!DECL_FIELD_IS_BASE (field) @@ -6822,7 +6886,10 @@ check_non_pod_aggregate (tree field) tree type = TREE_TYPE (field); if (TYPE_IDENTIFIER (type) == as_base_identifier) type = TYPE_CONTEXT (type); - if (!CLASS_TYPE_P (type) || !CLASSTYPE_NON_POD_AGGREGATE (type)) + if (!CLASS_TYPE_P (type) + || is_empty_class (type) + || (!CLASSTYPE_NON_POD_AGGREGATE (type) + && !CLASSTYPE_NON_AGGREGATE_POD (type))) return; tree size = end_of_class (type, (DECL_FIELD_IS_BASE (field) ? eoc_nvsize : eoc_nv_or_dsize)); @@ -6831,13 +6898,31 @@ check_non_pod_aggregate (tree field) { location_t loc = DECL_SOURCE_LOCATION (next); if (DECL_FIELD_IS_BASE (next)) - warning_at (loc, OPT_Wabi,"offset of %qT base class for " - "%<-std=c++14%> and up changes in " - "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next)); + { + if (abi_version_crosses (17) + && CLASSTYPE_NON_POD_AGGREGATE (type)) + warning_at (loc, OPT_Wabi,"offset of %qT base class for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next)); + else if (abi_version_crosses (21) + && CLASSTYPE_NON_AGGREGATE_POD (type)) + warning_at (loc, OPT_Wabi,"offset of %qT base class for " + "%<-std=c++20%> and up changes in " + "%<-fabi-version=21%> (GCC 16)", TREE_TYPE (next)); + } else - warning_at (loc, OPT_Wabi, "offset of %qD for " - "%<-std=c++14%> and up changes in " - "%<-fabi-version=17%> (GCC 12)", next); + { + if (abi_version_crosses (17) + && CLASSTYPE_NON_POD_AGGREGATE (type)) + warning_at (loc, OPT_Wabi, "offset of %qD for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", next); + else if (abi_version_crosses (21) + && CLASSTYPE_NON_AGGREGATE_POD (type)) + warning_at (loc, OPT_Wabi, "offset of %qD for " + "%<-std=c++20%> and up changes in " + "%<-fabi-version=21%> (GCC 16)", next); + } } } @@ -7842,6 +7927,17 @@ finish_struct_1 (tree t) return; } + if (location_t fcloc = failed_completion_location (t)) + { + auto_diagnostic_group adg; + if (warning (OPT_Wsfinae_incomplete_, + "defining %qT, which previously failed to be complete " + "in a SFINAE context", t) + && warn_sfinae_incomplete == 1) + inform (fcloc, "here. Use %qs for a diagnostic at that point", + "-Wsfinae-incomplete=2"); + } + /* If this type was previously laid out as a forward reference, make sure we lay it out again. */ TYPE_SIZE (t) = NULL_TREE; @@ -8261,6 +8357,15 @@ fixed_type_or_null (tree instance, int *nonnull, int *cdtorp) *nonnull = 1; return TREE_TYPE (instance); } + if (CLASS_TYPE_P (TREE_TYPE (instance))) + { + /* We missed a build_cplus_new somewhere, likely due to tf_decltype + mishandling. */ + gcc_checking_assert (false); + if (nonnull) + *nonnull = 1; + return TREE_TYPE (instance); + } return NULL_TREE; case SAVE_EXPR: @@ -10531,7 +10636,7 @@ build_vtbl_initializer (tree binfo, int i; if (init == size_zero_node) for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i) - CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init); + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init); else for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i) { @@ -10539,11 +10644,11 @@ build_vtbl_initializer (tree binfo, fn, build_int_cst (NULL_TREE, i)); TREE_CONSTANT (fdesc) = 1; - CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc); + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc); } } else - CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init); + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init); } } @@ -10882,6 +10987,17 @@ publicly_uniquely_derived_p (tree parent, tree type) return base && base != error_mark_node; } +/* TRUE iff TYPE is publicly & virtually derived from PARENT. */ + +bool +publicly_virtually_derived_p (tree parent, tree type) +{ + tree base = lookup_base (type, parent, + ba_ignore_scope | ba_check | ba_require_virtual, + NULL, tf_none); + return base && base != error_mark_node; +} + /* CTX1 and CTX2 are declaration contexts. Return the innermost common class between them, if any. */ diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 37ea65c..704d936 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -303,11 +303,20 @@ is_valid_constexpr_fn (tree fun, bool complain) } } } - else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun))) + else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)) && cxx_dialect < cxx26) { ret = false; if (complain) - error ("%q#T has virtual base classes", DECL_CONTEXT (fun)); + { + if (DECL_CONSTRUCTOR_P (fun)) + error ("%<constexpr%> constructor in %q#T that has " + "virtual base classes only available with " + "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun)); + else + error ("%<constexpr%> destructor in %q#T that has " + "virtual base classes only available with " + "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun)); + } } return ret; @@ -1048,6 +1057,12 @@ explain_invalid_constexpr_fn (tree fun) { static hash_set<tree> *diagnosed; tree body; + + /* Don't try to explain a function we already complained about. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + return; + /* In C++23, a function marked 'constexpr' may not actually be a constant expression. We haven't diagnosed the problem yet: -Winvalid-constexpr wasn't enabled. The function was called, so diagnose why it cannot be @@ -1097,17 +1112,14 @@ explain_invalid_constexpr_fn (tree fun) body = fd->body; else body = DECL_SAVED_TREE (fun); - body = massage_constexpr_body (fun, body); - require_potential_rvalue_constant_expression (body); + tree massaged = massage_constexpr_body (fun, body); + require_potential_rvalue_constant_expression (massaged); if (DECL_CONSTRUCTOR_P (fun)) { - cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true); + cx_check_missing_mem_inits (DECL_CONTEXT (fun), massaged, true); if (cxx_dialect > cxx11) - { - /* Also check the body, not just the ctor-initializer. */ - body = DECL_SAVED_TREE (fun); - require_potential_rvalue_constant_expression (body); - } + /* Also check the body, not just the ctor-initializer. */ + require_potential_rvalue_constant_expression (body); } } } @@ -1119,20 +1131,22 @@ explain_invalid_constexpr_fn (tree fun) struct GTY((for_user)) constexpr_call { /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; + constexpr_fundef *fundef = nullptr; /* Parameter bindings environment. A TREE_VEC of arguments. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. + tree bindings = NULL_TREE; + /* Result of the call, indexed by the value of + constexpr_ctx::manifestly_const_eval. + unknown_type_node means the call is being evaluated. error_mark_node means that the evaluation was erroneous or otherwise uncacheable (e.g. because it depends on the caller). Otherwise, the actual value of the call. */ - tree result; + tree results[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; /* The hash of this call; we remember it here to avoid having to recalculate it when expanding the hash table. */ - hashval_t hash; - /* The value of constexpr_ctx::manifestly_const_eval. */ - enum mce_value manifestly_const_eval; + hashval_t hash = 0; + + /* The result slot corresponding to the given mce_value. */ + tree& result (mce_value mce) { return results[1 + int(mce)]; } }; struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call> @@ -1427,8 +1441,6 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs) return true; if (lhs->hash != rhs->hash) return false; - if (lhs->manifestly_const_eval != rhs->manifestly_const_eval) - return false; if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef)) return false; return cp_tree_equal (lhs->bindings, rhs->bindings); @@ -1537,7 +1549,6 @@ static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree, static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree, bool * = NULL); static tree find_heap_var_refs (tree *, int *, void *); -static tree find_deleted_heap_var (tree *, int *, void *); /* Attempt to evaluate T which represents a call to a builtin function. We assume here that all builtin functions evaluate to scalar types @@ -1870,20 +1881,28 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data) static tree cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, - bool *non_constant_p, bool *overflow_p, - bool *non_constant_args) + tree orig_fun, bool *non_constant_p, + bool *overflow_p, bool *non_constant_args) { - const int nargs = call_expr_nargs (t); + int nargs = call_expr_nargs (t); tree parms = DECL_ARGUMENTS (fun); - int i; + int i, j = 0; + if (DECL_HAS_IN_CHARGE_PARM_P (fun) && fun != orig_fun) + ++nargs; + if (DECL_HAS_VTT_PARM_P (fun) + && fun != orig_fun + && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun) + || DECL_COMPLETE_DESTRUCTOR_P (orig_fun))) + ++nargs; /* We don't record ellipsis args below. */ int nparms = list_length (parms); int nbinds = nargs < nparms ? nargs : nparms; tree binds = make_tree_vec (nbinds); /* The call is not a constant expression if it involves the cdtor for a type - with virtual bases. */ - if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun)) + with virtual bases before C++26. */ + if (cxx_dialect < cxx26 + && (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))) { if (!ctx->quiet) { @@ -1901,7 +1920,30 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, tree type = parms ? TREE_TYPE (parms) : void_type_node; if (parms && DECL_BY_REFERENCE (parms)) type = TREE_TYPE (type); - x = get_nth_callarg (t, i); + if (i == 1 + && j == 0 + && DECL_HAS_IN_CHARGE_PARM_P (fun) + && orig_fun != fun) + { + if (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun) + || DECL_COMPLETE_DESTRUCTOR_P (orig_fun)) + x = boolean_true_node; + else + x = boolean_false_node; + j = -1; + } + else if (i == 2 + && j == -1 + && DECL_HAS_VTT_PARM_P (fun) + && orig_fun != fun + && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun) + || DECL_COMPLETE_DESTRUCTOR_P (orig_fun))) + { + x = build_zero_cst (type); + j = -2; + } + else + x = get_nth_callarg (t, i + j); /* For member function, the first argument is a pointer to the implied object. For a constructor, it might still be a dummy object, in which case we get the real argument from ctx. */ @@ -2520,10 +2562,7 @@ get_component_with_type (tree path, tree type, tree stop) dst_ptr + src2dst == src_ptr -1: unspecified relationship -2: src_type is not a public base of dst_type - -3: src_type is a multiple public non-virtual base of dst_type - - Since literal types can't have virtual bases, we only expect hint >=0, - -2, or -3. */ + -3: src_type is a multiple public non-virtual base of dst_type */ static tree cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, @@ -2560,6 +2599,22 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, if (*non_constant_p) return call; + /* For dynamic_cast from classes with virtual bases we can get something + like (virt_base *)(&d + 16) as OBJ. Try to convert that into + d.D.1234 using cxx_fold_indirect_ref. */ + if (cxx_dialect >= cxx26 && CONVERT_EXPR_P (obj)) + { + tree objo = obj; + STRIP_NOPS (objo); + if (TREE_CODE (objo) == POINTER_PLUS_EXPR) + { + objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)), + obj); + if (objo) + obj = build_fold_addr_expr (objo); + } + } + /* We expect OBJ to be in form of &d.D.2102 when HINT == 0, but when HINT is > 0, it can also be something like &d.D.2102 + 18446744073709551608, which includes the BINFO_OFFSET. */ @@ -2855,9 +2910,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { location_t loc = cp_expr_loc_or_input_loc (t); tree fun = get_function_named_in_call (t); - constexpr_call new_call - = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval }; - int depth_ok; if (fun == NULL_TREE) return cxx_eval_internal_function (ctx, t, lval, @@ -2910,6 +2962,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; } + tree orig_fun = fun; if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)) fun = DECL_CLONED_FUNCTION (fun); @@ -2946,12 +2999,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, gcc_assert (arg0); if (new_op_p) { - /* FIXME: We should not get here; the VERIFY_CONSTANT above - should have already caught it. But currently a conversion - from pointer type to arithmetic type is only considered - non-constant for CONVERT_EXPRs, not NOP_EXPRs. */ if (!tree_fits_uhwi_p (arg0)) { + /* We should not get here; the VERIFY_CONSTANT above + should have already caught it. */ + gcc_checking_assert (false); if (!ctx->quiet) error_at (loc, "cannot allocate array: size not constant"); *non_constant_p = true; @@ -2966,14 +3018,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, : heap_uninit_identifier, type); DECL_ARTIFICIAL (var) = 1; - TREE_STATIC (var) = 1; - // Temporarily register the artificial var in varpool, - // so that comparisons of its address against NULL are folded - // through nonzero_address even with - // -fno-delete-null-pointer-checks or that comparison of - // addresses of different heap artificial vars is folded too. - // See PR98988 and PR99031. - varpool_node::finalize_decl (var); ctx->global->heap_vars.safe_push (var); ctx->global->put_value (var, NULL_TREE); return fold_convert (ptr_type_node, build_address (var)); @@ -3082,6 +3126,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } constexpr_ctx new_ctx = *ctx; + ctx = &new_ctx; if (DECL_CONSTRUCTOR_P (fun) && !ctx->object && TREE_CODE (t) == AGGR_INIT_EXPR) { @@ -3091,29 +3136,28 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL); CONSTRUCTOR_NO_CLEARING (ctor) = true; ctx->global->put_value (new_ctx.object, ctor); - ctx = &new_ctx; } /* An immediate invocation is manifestly constant evaluated including the arguments of the call, so use mce_true even for the argument evaluation. */ if (DECL_IMMEDIATE_FUNCTION_P (fun)) - { - new_ctx.manifestly_const_eval = mce_true; - new_call.manifestly_const_eval = mce_true; - ctx = &new_ctx; - } + new_ctx.manifestly_const_eval = mce_true; /* We used to shortcut trivial constructor/op= here, but nowadays we can only get a trivial function here with -fno-elide-constructors. */ gcc_checking_assert (!trivial_fn_p (fun) || !flag_elide_constructors + /* Or it's a call from maybe_thunk_body (111075). */ + || (TREE_CODE (t) == CALL_EXPR ? CALL_FROM_THUNK_P (t) + : AGGR_INIT_FROM_THUNK_P (t)) /* We don't elide constructors when processing a noexcept-expression. */ || cp_noexcept_operand); bool non_constant_args = false; + constexpr_call new_call; new_call.bindings - = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p, + = cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p, overflow_p, &non_constant_args); /* We build up the bindings list before we know whether we already have this @@ -3185,7 +3229,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } } - depth_ok = push_cx_call_context (t); + /* Don't complain about problems evaluating an ill-formed function. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + new_ctx.quiet = true; + + int depth_ok = push_cx_call_context (t); /* Remember the object we are constructing or destructing. */ tree new_obj = NULL_TREE; @@ -3227,8 +3276,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef); new_call.hash = iterative_hash_template_arg (new_call.bindings, new_call.hash); - new_call.hash - = iterative_hash_object (ctx->manifestly_const_eval, new_call.hash); /* If we have seen this call before, we are done. */ maybe_initialize_constexpr_call_table (); @@ -3246,22 +3293,23 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, the slot can move during evaluation of the body. */ *slot = entry = ggc_alloc<constexpr_call> (); *entry = new_call; + entry->result (ctx->manifestly_const_eval) = unknown_type_node; fb.preserve (); } } - /* Calls that are in progress have their result set to NULL, so that we - can detect circular dependencies. Now that we only cache up to - constexpr_cache_depth this won't catch circular dependencies that + /* Calls that are in progress have their result set to unknown_type_node, + so that we can detect circular dependencies. Now that we only cache + up to constexpr_cache_depth this won't catch circular dependencies that start deeper, but they'll hit the recursion or ops limit. */ - else if (entry->result == NULL) + else if (entry->result (ctx->manifestly_const_eval) == unknown_type_node) { if (!ctx->quiet) error ("call has circular dependency"); *non_constant_p = true; - entry->result = result = error_mark_node; + entry->result (ctx->manifestly_const_eval) = result = error_mark_node; } else - result = entry->result; + result = entry->result (ctx->manifestly_const_eval); } if (!depth_ok) @@ -3441,11 +3489,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cacheable = false; break; } - /* And don't cache a ref to a deleted heap variable (119162). */ - if (cacheable - && (cp_walk_tree_without_duplicates - (&result, find_deleted_heap_var, NULL))) - cacheable = false; } /* Rewrite all occurrences of the function's RESULT_DECL with the @@ -3482,7 +3525,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, else if (!result) result = void_node; if (entry) - entry->result = cacheable ? result : error_mark_node; + { + entry->result (ctx->manifestly_const_eval) + = cacheable ? result : error_mark_node; + + if (result != error_mark_node + && ctx->manifestly_const_eval == mce_unknown) + { + /* Evaluation succeeded and was independent of whether we're in a + manifestly constant-evaluated context, so we can also reuse + this result when evaluating this call with a fixed context. */ + if (!entry->result (mce_true)) + entry->result (mce_true) = entry->result (mce_unknown); + if (!entry->result (mce_false)) + entry->result (mce_false) = entry->result (mce_unknown); + } + } } /* The result of a constexpr function must be completely initialized. @@ -3503,11 +3561,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, /* Return true if T is a valid constant initializer. If a CONSTRUCTOR initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be - cleared. + cleared. If called recursively on a FIELD_DECL's CONSTRUCTOR, SZ + is DECL_SIZE of the FIELD_DECL, otherwise NULL. FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ bool -reduced_constant_expression_p (tree t) +reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */) { if (t == NULL_TREE) return false; @@ -3518,6 +3577,9 @@ reduced_constant_expression_p (tree t) /* Even if we can't lower this yet, it's constant. */ return true; + case OMP_DECLARE_MAPPER: + return true; + case CONSTRUCTOR: /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */ tree field; @@ -3572,7 +3634,12 @@ reduced_constant_expression_p (tree t) { /* If VAL is null, we're in the middle of initializing this element. */ - if (!reduced_constant_expression_p (e.value)) + if (!reduced_constant_expression_p (e.value, + (e.index + && (TREE_CODE (e.index) + == FIELD_DECL)) + ? DECL_SIZE (e.index) + : NULL_TREE)) return false; /* We want to remove initializers for empty fields in a struct to avoid confusing output_constructor. */ @@ -3592,7 +3659,16 @@ reduced_constant_expression_p (tree t) /* There could be a non-empty field at the end. */ for (; field; field = next_subobject_field (DECL_CHAIN (field))) if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false)) - return false; + { + /* Ignore FIELD_DECLs with bit positions beyond DECL_SIZE of + the parent FIELD_DECL (if any) for classes with virtual + bases. */ + if (cxx_dialect >= cxx26 + && sz + && tree_int_cst_le (sz, bit_position (field))) + break; + return false; + } ok: if (CONSTRUCTOR_NO_CLEARING (t)) /* All the fields are initialized. */ @@ -5854,6 +5930,20 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, unsigned HOST_WIDE_INT const_nunits; if (off == 0 && similar_type_p (optype, type)) return op; + else if (cxx_dialect >= cxx26 + && VAR_P (op) + && DECL_VTABLE_OR_VTT_P (op) + && same_type_ignoring_top_level_qualifiers_p (type, + ptrdiff_type_node) + && POINTER_TYPE_P (strip_array_types (optype))) + { + /* We often read some virtual table elements using ptrdiff_t rather + than pointer type. */ + if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, + strip_array_types (optype), + op, off, empty_base)) + return fold_convert (type, ret); + } else if (TREE_CODE (optype) == COMPLEX_TYPE && similar_type_p (type, TREE_TYPE (optype))) { @@ -5947,8 +6037,13 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, if (!tree_fits_uhwi_p (pos)) continue; unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos); - unsigned HOST_WIDE_INT el_sz - = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); + unsigned HOST_WIDE_INT el_sz; + if (DECL_FIELD_IS_BASE (field) + && CLASS_TYPE_P (optype) + && CLASSTYPE_VBASECLASSES (optype)) + el_sz = tree_to_uhwi (DECL_SIZE_UNIT (field)); + else + el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); if (upos <= off && off < upos + el_sz) { tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), @@ -5999,6 +6094,25 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, offset positive, so that cxx_fold_indirect_ref_1 can identify more folding opportunities. */ auto canonicalize_obj_off = [] (tree& obj, tree& off) { + if (cxx_dialect >= cxx26) + { + /* For C++26, we need to fold *(B *)(&x.D.1234 + 32) used + to access virtual base members. */ + tree nobj = obj; + while (TREE_CODE (nobj) == COMPONENT_REF + && DECL_FIELD_IS_BASE (TREE_OPERAND (nobj, 1))) + nobj = TREE_OPERAND (nobj, 0); + if (nobj != obj + && CLASS_TYPE_P (TREE_TYPE (nobj)) + && CLASSTYPE_VBASECLASSES (TREE_TYPE (nobj))) + while (obj != nobj) + { + tree field = TREE_OPERAND (obj, 1); + tree pos = byte_position (field); + off = int_const_binop (PLUS_EXPR, off, pos); + obj = TREE_OPERAND (obj, 0); + } + } while (TREE_CODE (obj) == COMPONENT_REF /* We need to preserve union member accesses so that we can later properly diagnose accessing the wrong member. */ @@ -6037,8 +6151,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, { tree off = integer_zero_node; canonicalize_obj_off (op, off); - gcc_assert (integer_zerop (off)); - return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base); + return cxx_fold_indirect_ref_1 (ctx, loc, type, op, + tree_to_uhwi (off), empty_base); } } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR @@ -6399,7 +6513,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (TREE_CLOBBER_P (init) && CLOBBER_KIND (init) < CLOBBER_OBJECT_END) - /* Only handle clobbers ending the lifetime of objects. */ + /* Only handle clobbers ending the lifetime of objects. + ??? We should probably set CONSTRUCTOR_NO_CLEARING. */ return void_node; /* First we figure out where we're storing to. */ @@ -7827,6 +7942,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case LABEL_EXPR: case CASE_LABEL_EXPR: case PREDICT_EXPR: + case OMP_DECLARE_MAPPER: return t; case PARM_DECL: @@ -8450,7 +8566,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type) && INDIRECT_TYPE_P (TREE_TYPE (op)) - && ctx->manifestly_const_eval == mce_true) + && ctx->strict) { if (!ctx->quiet) error_at (loc, @@ -8602,7 +8718,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, tree cookie_size = NULL_TREE; tree arg_size = NULL_TREE; if (TREE_CODE (elt_type) == RECORD_TYPE - && TYPE_NAME (elt_type) == heap_identifier) + && TYPE_IDENTIFIER (elt_type) == heap_identifier) { tree fld1 = TYPE_FIELDS (elt_type); tree fld2 = DECL_CHAIN (fld1); @@ -8997,20 +9113,6 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/) return NULL_TREE; } -/* Look for deleted heap variables in the expression *TP. */ - -static tree -find_deleted_heap_var (tree *tp, int *walk_subtrees, void */*data*/) -{ - if (VAR_P (*tp) - && DECL_NAME (*tp) == heap_deleted_identifier) - return *tp; - - if (TYPE_P (*tp)) - *walk_subtrees = 0; - return NULL_TREE; -} - /* Find immediate function decls in *TP if any. */ static tree @@ -9116,6 +9218,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree fndecl = cp_get_callee_fndecl_nofold (x); if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) is_consteval = true; + /* Don't try to evaluate a std::vector constructor taking an integer, it + will fail in the 'if (heap_var)' block below after doing all the work + (c++/113835). This will need adjustment if P3554 is accepted. Note + that evaluation of e.g. the vector default constructor can succeed, so + we don't shortcut all vector constructors. */ + if (fndecl && DECL_CONSTRUCTOR_P (fndecl) && allow_non_constant + && is_std_class (type, "vector") && call_expr_nargs (x) > 1 + && TREE_CODE (TREE_TYPE (get_nth_callarg (x, 1))) == INTEGER_TYPE) + return t; } if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) { @@ -9190,11 +9301,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (r == void_node && !constexpr_dtor && ctx.ctor) r = ctx.ctor; - if (!constexpr_dtor) - verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - else - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; - unsigned int i; tree cleanup; /* Evaluate the cleanups. */ @@ -9213,15 +9319,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } - if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) - { - if (!allow_non_constant) - error ("%qE is not a constant expression because it refers to " - "an incompletely initialized variable", t); - TREE_CONSTANT (r) = false; - non_constant_p = true; - } - if (!non_constant_p && cxx_dialect >= cxx20 && !global_ctx.heap_vars.is_empty ()) { @@ -9231,9 +9328,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (heap_var) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because it refers to " - "a result of %<operator new%>", t); + { + error ("%qE is not a constant expression because it refers to " + "a result of %<operator new%>", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9242,13 +9341,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (DECL_NAME (heap_var) != heap_deleted_identifier) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because allocated " - "storage has not been deallocated", t); + { + error ("%qE is not a constant expression because allocated " + "storage has not been deallocated", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } - varpool_node::get (heap_var)->remove (); } } @@ -9274,6 +9374,20 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } + if (!non_constant_p && !constexpr_dtor) + verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); + + /* After verify_constant because reduced_constant_expression_p can unset + CONSTRUCTOR_NO_CLEARING. */ + if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + { + if (!allow_non_constant) + error ("%qE is not a constant expression because it refers to " + "an incompletely initialized variable", t); + TREE_CONSTANT (r) = false; + non_constant_p = true; + } + if (non_constant_p) /* If we saw something bad, go back to our argument. The wrapping below is only for the cases of TREE_CONSTANT argument or overflow. */ @@ -9290,13 +9404,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (non_constant_p && !allow_non_constant) return error_mark_node; - else if (constexpr_dtor) - return r; else if (non_constant_p && TREE_CONSTANT (r)) r = mark_non_constant (r); else if (non_constant_p) return t; + if (constexpr_dtor) + { + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; + return r; + } + /* Check we are not trying to return the wrong type. */ if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (r))) { @@ -9316,7 +9434,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_INITIAL (t) == r) return t; - else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR) + else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR + || TREE_CODE (t) == AGGR_INIT_EXPR) /* Don't add a TARGET_EXPR if our argument didn't have one. */; else if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_CLEANUP (t)) r = get_target_expr (r); @@ -9447,6 +9566,9 @@ fold_simple (tree t) tree fold_to_constant (tree t) { + if (processing_template_decl) + return t; + tree r = fold (t); if (CONSTANT_CLASS_P (r) && !TREE_OVERFLOW (r)) return r; @@ -9466,8 +9588,35 @@ tree maybe_constant_value (tree t, tree decl /* = NULL_TREE */, mce_value manifestly_const_eval /* = mce_unknown */) { + tree orig_t = t; tree r; + if (EXPR_P (t) && manifestly_const_eval == mce_unknown) + { + /* Look up each operand in the cv_cache first to see if we've already + reduced it, and reuse that result to avoid quadratic behavior if + we're called when building up a large expression. */ + int n = cp_tree_operand_length (t); + tree *ops = XALLOCAVEC (tree, n); + bool rebuild = false; + for (int i = 0; i < n; ++i) + { + ops[i] = TREE_OPERAND (t, i); + if (tree *cached = hash_map_safe_get (cv_cache, ops[i])) + if (*cached != ops[i]) + { + ops[i] = *cached; + rebuild = true; + } + } + if (rebuild) + { + t = copy_node (t); + for (int i = 0; i < n; ++i) + TREE_OPERAND (t, i) = ops[i]; + } + } + if (!is_nondependent_constant_expression (t)) { if (TREE_OVERFLOW_P (t) @@ -9485,6 +9634,10 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */, return fold_to_constant (t); if (manifestly_const_eval != mce_unknown) + /* TODO: Extend the cache to be mce_value aware. And if we have a + previously cached mce_unknown result that's TREE_CONSTANT, it means + the reduced value is independent of mce_value and so we should + be able to reuse it in the mce_true/false case. */ return cxx_eval_outermost_constant_expr (t, true, true, manifestly_const_eval, false, decl); @@ -9514,7 +9667,7 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */, || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) || !cp_tree_equal (r, t)); if (!c.evaluation_restricted_p ()) - cv_cache->put (t, r); + cv_cache->put (orig_t, r); return r; } @@ -9678,7 +9831,7 @@ fold_non_dependent_init (tree t, static tree maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, - bool manifestly_const_eval) + mce_value manifestly_const_eval) { if (!t) return t; @@ -9704,17 +9857,27 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, { /* [basic.start.static] allows constant-initialization of variables with static or thread storage duration even if it isn't required, but we - shouldn't bend the rules the same way for automatic variables. */ + shouldn't bend the rules the same way for automatic variables. + + But still enforce the requirements of constexpr/constinit. + [dcl.constinit] "If a variable declared with the constinit specifier + has dynamic initialization, the program is ill-formed, even if the + implementation would perform that initialization as a static + initialization." */ bool is_static = (decl && DECL_P (decl) && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); + bool strict = (!is_static + || (decl && DECL_P (decl) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_DECLARED_CONSTINIT_P (decl)))); if (is_static) - manifestly_const_eval = true; + manifestly_const_eval = mce_true; - if (cp_unevaluated_operand && !manifestly_const_eval) + if (cp_unevaluated_operand && manifestly_const_eval != mce_true) return fold_to_constant (t); - t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static, - mce_value (manifestly_const_eval), + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict, + manifestly_const_eval, false, decl); } if (TREE_CODE (t) == TARGET_EXPR) @@ -9731,6 +9894,12 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, tree maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) { + return maybe_constant_init_1 (t, decl, true, mce_value (manifestly_const_eval)); +} + +tree +maybe_constant_init (tree t, tree decl, mce_value manifestly_const_eval) +{ return maybe_constant_init_1 (t, decl, true, manifestly_const_eval); } @@ -9739,7 +9908,7 @@ maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) tree cxx_constant_init (tree t, tree decl) { - return maybe_constant_init_1 (t, decl, false, true); + return maybe_constant_init_1 (t, decl, false, mce_true); } #if 0 @@ -10498,6 +10667,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, "expression", t); return false; + case OMP_DECLARE_MAPPER: + /* This can be used to initialize VAR_DECLs: it's treated as a magic + constant. */ + return true; + case ASM_EXPR: if (flags & tf_error) inline_asm_in_constexpr_error (loc, fundef_p); @@ -10945,6 +11119,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, *jump_target = *target; return true; } + if (DECL_ARTIFICIAL (*target)) + /* The user didn't write this goto, this isn't the problem. */ + return true; if (flags & tf_error) constexpr_error (loc, fundef_p, "%<goto%> is not a constant " "expression"); @@ -10978,6 +11155,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CO_AWAIT_EXPR: case CO_YIELD_EXPR: case CO_RETURN_EXPR: + if (flags & tf_error) + constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p, + "%qE is not a constant expression", t); return false; /* Assume a TU-local entity is not constant, we'll error later when diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index a9caba8..c8eef24 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -354,7 +354,7 @@ struct norm_info : subst_info /* Construct a top-level context for DECL. */ norm_info (tree in_decl, bool diag) - : subst_info (tf_warning_or_error, in_decl), + : subst_info (tf_warning_or_error|tf_partial, in_decl), generate_diagnostics (diag) { if (in_decl) @@ -1836,7 +1836,7 @@ tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_ static bool satisfying_constraint; /* A vector of incomplete types (and of declarations with undeduced return type), - appended to by note_failed_type_completion_for_satisfaction. The + appended to by note_failed_type_completion. The satisfaction caches use this in order to keep track of "potentially unstable" satisfaction results. @@ -1845,21 +1845,69 @@ static bool satisfying_constraint; static GTY((deletable)) vec<tree, va_gc> *failed_type_completions; +/* A map of where types were found to be incomplete in SFINAE context, for + warning if they are later completed. */ + +static GTY((cache)) hash_map<tree, location_t, decl_location_traits> *failed_completions_map; + /* Called whenever a type completion (or return type deduction) failure occurs that definitely affects the meaning of the program, by e.g. inducing substitution failure. */ void -note_failed_type_completion_for_satisfaction (tree t) +note_failed_type_completion (tree t, tsubst_flags_t complain) { + if (dependent_template_arg_p (t)) + return; + + gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t)) + || (DECL_P (t) && undeduced_auto_decl (t))); + if (satisfying_constraint) + vec_safe_push (failed_type_completions, t); + + if (TYPE_P (t)) { - gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t)) - || (DECL_P (t) && undeduced_auto_decl (t))); - vec_safe_push (failed_type_completions, t); + if (!CLASS_TYPE_P (t)) + return; + t = TYPE_MAIN_DECL (t); + } + if (!(complain & tf_error) + && warning_enabled_at (DECL_SOURCE_LOCATION (t), + OPT_Wsfinae_incomplete_)) + { + if (warn_sfinae_incomplete > 1) + { + if (TREE_CODE (t) == TYPE_DECL) + warning (OPT_Wsfinae_incomplete_, + "failed to complete %qT in SFINAE context", TREE_TYPE (t)); + else + warning (OPT_Wsfinae_incomplete_, + "failed to deduce %qD in SFINAE context", t); + } + if (!failed_completions_map) + failed_completions_map + = hash_map<tree, location_t, decl_location_traits>::create_ggc (); + failed_completions_map->put (t, input_location); } } +/* If T was previously found to be incomplete in SFINAE context, return the + location where that happened, otherwise UNKNOWN_LOCATION. */ + +location_t +failed_completion_location (tree t) +{ + if (failed_completions_map) + { + if (TYPE_P (t)) + t = TYPE_MAIN_DECL (t); + if (location_t *p = failed_completions_map->get (t)) + return *p; + } + return UNKNOWN_LOCATION; +} + /* Returns true if the range [BEGIN, END) of elements within the failed_type_completions vector contains a complete type (or a declaration with a non-placeholder return type). */ @@ -2704,6 +2752,8 @@ satisfy_declaration_constraints (tree t, sat_info info) static tree satisfy_declaration_constraints (tree t, tree args, sat_info info) { + tree orig_args = args; + /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2732,7 +2782,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) tree result = boolean_true_node; if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ())) { - if (!push_tinst_level (t, args)) + if (!push_tinst_level (t, orig_args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_to_top_level (); @@ -3098,6 +3148,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_CONVERTIBLE: inform (loc, " %qT is not convertible from %qE", t2, t1); break; + case CPTK_IS_DESTRUCTIBLE: + inform (loc, " %qT is not destructible", t1); + break; case CPTK_IS_EMPTY: inform (loc, " %qT is not an empty class", t1); break; @@ -3143,6 +3196,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_NOTHROW_CONVERTIBLE: inform (loc, " %qT is not nothrow convertible from %qE", t2, t1); break; + case CPTK_IS_NOTHROW_DESTRUCTIBLE: + inform (loc, " %qT is not nothrow destructible", t1); + break; case CPTK_IS_NOTHROW_INVOCABLE: if (!t2) inform (loc, " %qT is not nothrow invocable", t1); @@ -3192,6 +3248,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_TRIVIALLY_COPYABLE: inform (loc, " %qT is not trivially copyable", t1); break; + case CPTK_IS_TRIVIALLY_DESTRUCTIBLE: + inform (loc, " %qT is not trivially destructible", t1); + break; case CPTK_IS_UNBOUNDED_ARRAY: inform (loc, " %qT is not an unbounded array", t1); break; @@ -3207,6 +3266,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_RANK: inform (loc, " %qT cannot yield a rank", t1); break; + case CPTK_TYPE_ORDER: + inform (loc, " %qT and %qT cannot be ordered", t1, t2); + break; case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: inform (loc, " %qT is not a reference that binds to a temporary " "object of type %qT (direct-initialization)", t1, t2); diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index f2b126c..d0cfd2e 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -860,10 +860,17 @@ cp_contract_assertion_p (const_tree attr) void remove_contract_attributes (tree fndecl) { + if (!flag_contracts) + return; + tree list = NULL_TREE; for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p)) if (!cxx_contract_attribute_p (p)) - list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list); + { + tree nl = copy_node (p); + TREE_CHAIN (nl) = list; + list = nl; + } DECL_ATTRIBUTES (fndecl) = nreverse (list); } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index b92d09f..52cc186 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -191,8 +191,87 @@ static bool coro_promise_type_found_p (tree, location_t); just syntactic sugar for a co_await). We defer the analysis and transformation until template expansion is - complete so that we have complete types at that time. */ + complete so that we have complete types at that time. + --------------------------------------------------------------------------- + + Coroutine state, and responsibility for its release. + + As noted above, a coroutine has some state that persists across suspensions. + + The state has two components: + * State that is specified by the standard and persists for the entire + life of the coroutine. + * Local state that is constructed/destructed as scopes in the original + function body are entered/exited. The destruction of local state is + always the responsibility of the body code. + + The persistent state (and the overall storage for the state) must be + managed in two places: + * The ramp function (which allocates and builds this - and can, in some + cases, be responsible for destroying it) + * The re-written function body which can destroy it when that body + completes its final suspend - or when the handle.destroy () is called. + + In all cases the ramp holds responsibility for constructing the standard- + mandated persistent state. + + There are four ways in which the ramp might be re-entered after starting + the function body: + A The body could suspend (one might expect that to be the 'normal' case + for most coroutines). + B The body might complete either synchronously or via continuations. + C An exception might be thrown during the setup of the initial await + expression, before the initial awaiter resumes. + D An exception might be processed by promise.unhandled_exception () and + that, in turn, might re-throw it (or throw something else). In this + case, the coroutine is considered suspended at the final suspension + point. + + Until the ramp return value has been constructed, the ramp is considered + to have a use of the state. + + To manage these interacting conditions we allocate a reference counter + for the frame state. This is initialised to 1 by the ramp as part of its + startup (note that failures/exceptions in the startup code are handled + locally to the ramp). + + When the body returns (either normally, or by exception) the ramp releases + its use. + + Once the rewritten coroutine body is started, the body is considered to + have a use of the frame. This use (potentially) needs to be released if + an exception is thrown from the body. We implement this using an eh-only + cleanup around the initial await and function body. If we have the case + D above, then we do not release the use. + + In case: + + A, typically the ramp would be re-entered with the body holding a use, + and therefore the ramp should not destroy the state. + + B, both the body and ramp will have released their uses, and the ramp + should destroy the state. + + C, we must arrange for the body to release its use, because we require + the ramp to cleanup in this circumstance. + + D is an outlier, since the responsibility for destruction of the state + now rests with the user's code (via a handle.destroy() call). + + NOTE: In the case that the body has never suspended before such an + exception occurs, the only reasonable way for the user code to obtain the + necessary handle is if unhandled_exception() throws the handle or some + object that contains the handle. That is outside of the designs here - + if the user code might need this corner-case, then such provision will + have to be made. + + In the ramp, we implement destruction for the persistent frame state by + means of cleanups. These are run conditionally when the reference count + is 0 signalling that both the body and the ramp have completed. + + In the body, once we pass the final suspend, then we test the use and + delete the state if the use is 0. */ /* The state that we collect during parsing (and template expansion) for a coroutine. */ @@ -206,11 +285,10 @@ struct GTY((for_user)) coroutine_info tree traits_type; /* The cached traits type for this function. */ tree handle_type; /* The cached coroutine handle for this function. */ tree self_h_proxy; /* A handle instance that is used as the proxy for the - one that will eventually be allocated in the coroutine - frame. */ + one that will eventually be built in lowering. */ tree promise_proxy; /* Likewise, a proxy promise instance. */ - tree from_address; /* handle_type from_address function. */ - tree return_void; /* The expression for p.return_void() if it exists. */ + tree from_address; /* handle_type from_address() function. */ + tree return_void; /* The expression for p.return_void(), if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this function into a coroutine. */ @@ -348,6 +426,7 @@ static GTY(()) tree coro_resume_index_id; static GTY(()) tree coro_self_handle_id; static GTY(()) tree coro_actor_continue_id; static GTY(()) tree coro_frame_i_a_r_c_id; +static GTY(()) tree coro_frame_refcount_id; /* Create the identifiers used by the coroutines library interfaces and the implementation frame state. */ @@ -385,6 +464,7 @@ coro_init_identifiers () coro_resume_index_id = get_identifier ("_Coro_resume_index"); coro_self_handle_id = get_identifier ("_Coro_self_handle"); coro_actor_continue_id = get_identifier ("_Coro_actor_continue"); + coro_frame_refcount_id = get_identifier ("_Coro_frame_refcount"); } /* Trees we only need to set up once. */ @@ -1277,8 +1357,14 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, if (TREE_CODE (o_type) != RECORD_TYPE) { - error_at (loc, "awaitable type %qT is not a structure", - o_type); + if (suspend_kind == FINAL_SUSPEND_POINT) + error_at (loc, "%qs awaitable type %qT is not a structure", + "final_suspend()", o_type); + else if (suspend_kind == INITIAL_SUSPEND_POINT) + error_at (loc, "%qs awaitable type %qT is not a structure", + "initial_suspend()", o_type); + else + error_at (loc, "awaitable type %qT is not a structure", o_type); return error_mark_node; } @@ -1461,6 +1547,12 @@ finish_co_await_expr (location_t kw, tree expr) if (!expr || error_operand_p (expr)) return error_mark_node; + if (cp_unevaluated_operand) + { + error_at (kw, "%qs cannot be used in an unevaluated context","co_await"); + return error_mark_node; + } + if (!coro_common_keyword_context_valid_p (current_function_decl, kw, "co_await")) return error_mark_node; @@ -1541,6 +1633,12 @@ finish_co_yield_expr (location_t kw, tree expr) if (!expr || error_operand_p (expr)) return error_mark_node; + if (cp_unevaluated_operand) + { + error_at (kw, "%qs cannot be used in an unevaluated context","co_yield"); + return error_mark_node; + } + /* Check the general requirements and simple syntax errors. */ if (!coro_common_keyword_context_valid_p (current_function_decl, kw, "co_yield")) @@ -1852,21 +1950,6 @@ coro_build_frame_access_expr (tree coro_ref, tree member_id, bool preserve_ref, return expr; } -/* Helpers to build EXPR_STMT and void-cast EXPR_STMT, common ops. */ - -static tree -coro_build_expr_stmt (tree expr, location_t loc) -{ - return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr)); -} - -static tree -coro_build_cvt_void_expr_stmt (tree expr, location_t loc) -{ - tree t = build1 (CONVERT_EXPR, void_type_node, expr); - return coro_build_expr_stmt (t, loc); -} - /* Helpers to build an artificial var, with location LOC, NAME and TYPE, in CTX, and with initializer INIT. */ @@ -1979,12 +2062,13 @@ struct coro_aw_data tree coro_fp; /* Frame pointer var. */ tree resume_idx; /* This is the index var in the frame. */ tree i_a_r_c; /* initial suspend await_resume() was called if true. */ - tree self_h; /* This is a handle to the current coro (frame var). */ tree cleanup; /* This is where to go once we complete local destroy. */ tree cororet; /* This is where to go if we suspend. */ tree corocont; /* This is where to go if we continue. */ tree dispatch; /* This is where we go if we restart the dispatch. */ tree conthand; /* This is the handle for a continuation. */ + tree handle_type; /* Handle type for this coroutine... */ + tree hfa_m; /* ... and handle.from_address() for this. */ unsigned index; /* This is our current resume index. */ }; @@ -2042,8 +2126,10 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d) tree awaiter_calls = TREE_OPERAND (saved_co_await, 3); tree source = TREE_OPERAND (saved_co_await, 4); - bool is_final = (source - && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT); + bool is_final + = (source && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT); + bool is_initial + = (source && TREE_INT_CST_LOW (source) == (int) INITIAL_SUSPEND_POINT); /* Build labels for the destinations of the control flow when we are resuming or destroying. */ @@ -2100,6 +2186,18 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d) tree suspend = TREE_VEC_ELT (awaiter_calls, 1); /* await_suspend(). */ tree susp_type = TREE_TYPE (suspend); + tree susp_call = suspend; + if (TREE_CODE (suspend) == TARGET_EXPR) + susp_call = TARGET_EXPR_INITIAL (suspend); + gcc_checking_assert (TREE_CODE (susp_call) == CALL_EXPR); + tree dummy_ch = build_dummy_object (data->handle_type); + r = fold_convert (build_pointer_type (void_type_node), data->coro_fp); + vec<tree, va_gc> *args = make_tree_vector_single (r); + tree hfa = cp_fold_rvalue ( + build_new_method_call (dummy_ch, data->hfa_m, &args, NULL_TREE, + LOOKUP_NORMAL, NULL, tf_warning_or_error)); + release_tree_vector (args); + CALL_EXPR_ARG (susp_call, call_expr_nargs (susp_call) - 1) = hfa; bool is_cont = false; /* NOTE: final suspend can't resume; the "resume" label in that case @@ -2171,6 +2269,13 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d) /* Resume point. */ add_stmt (build_stmt (loc, LABEL_EXPR, resume_label)); + if (is_initial && data->i_a_r_c) + { + r = cp_build_modify_expr (loc, data->i_a_r_c, NOP_EXPR, boolean_true_node, + tf_warning_or_error); + finish_expr_stmt (r); + } + /* This will produce the value (if one is provided) from the co_await expression. */ tree resume_call = TREE_VEC_ELT (awaiter_calls, 2); /* await_resume(). */ @@ -2412,6 +2517,11 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, bool spf = start_preparsed_function (actor, NULL_TREE, SF_PRE_PARSED); gcc_checking_assert (spf); gcc_checking_assert (cfun && current_function_decl && TREE_STATIC (actor)); + if (flag_exceptions) + /* We, unconditionally, add a try/catch and rethrow. + TODO: Determine if the combination of initial suspend and the original + body cannot throw, and elide these additions. */ + cp_function_chain->can_throw = true; tree stmt = begin_function_body (); tree actor_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); @@ -2558,8 +2668,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Finish the resume dispatcher. */ finish_switch_stmt (dispatcher); - finish_else_clause (lsb_if); + finish_else_clause (lsb_if); finish_if_stmt (lsb_if); /* If we reach here then we've hit UB. */ @@ -2569,22 +2679,16 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Now we start building the rewritten function body. */ add_stmt (build_stmt (loc, LABEL_EXPR, actor_begin_label)); - /* actor's coroutine 'self handle'. */ - tree ash = coro_build_frame_access_expr (actor_frame, coro_self_handle_id, - false, tf_warning_or_error); - /* So construct the self-handle from the frame address. */ - tree hfa_m = get_coroutine_from_address (orig); - /* Should have been set earlier by coro_promise_type_found_p. */ - gcc_assert (hfa_m); - - tree r = build1 (CONVERT_EXPR, build_pointer_type (void_type_node), actor_fp); - vec<tree, va_gc> *args = make_tree_vector_single (r); - tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL, - NULL, tf_warning_or_error); - r = cp_build_init_expr (ash, hfa); - r = coro_build_cvt_void_expr_stmt (r, loc); - add_stmt (r); - release_tree_vector (args); + tree i_a_r_c = NULL_TREE; + if (flag_exceptions) + { + i_a_r_c + = coro_build_frame_access_expr (actor_frame, coro_frame_i_a_r_c_id, + false, tf_warning_or_error); + tree m = cp_build_modify_expr (loc, i_a_r_c, NOP_EXPR, + boolean_false_node, tf_warning_or_error); + finish_expr_stmt (m); + } /* Now we know the real promise, and enough about the frame layout to decide where to put things. */ @@ -2599,69 +2703,74 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Add in our function body with the co_returns rewritten to final form. */ add_stmt (fnbody); - /* now do the tail of the function. */ + /* We are done with the frame, but if the ramp still has a hold on it + we should not cleanup. So decrement the refcount and then return to + the ramp if it is > 0. */ + tree coro_frame_refcount + = coro_build_frame_access_expr (actor_frame, coro_frame_refcount_id, + false, tf_warning_or_error); + tree released = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node, + coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 1)); + tree r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released, + tf_warning_or_error); + finish_expr_stmt (r); + tree cond = build2_loc (loc, NE_EXPR, short_unsigned_type_node, + coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 0)); + tree ramp_cu_if = begin_if_stmt (); + finish_if_stmt_cond (cond, ramp_cu_if); + finish_return_stmt (NULL_TREE); + finish_then_clause (ramp_cu_if); + finish_if_stmt (ramp_cu_if); + + /* Otherwise, do the tail of the function; first cleanups. */ r = build_stmt (loc, LABEL_EXPR, del_promise_label); add_stmt (r); - /* Destructors for the things we built explicitly. */ + /* Destructors for the things we built explicitly. + promise... */ if (tree c = cxx_maybe_build_cleanup (promise_proxy, tf_warning_or_error)) - add_stmt (c); - - tree del_frame_label - = create_named_label_with_ctx (loc, "coro.delete.frame", actor); - r = build_stmt (loc, LABEL_EXPR, del_frame_label); - add_stmt (r); - - /* Here deallocate the frame (if we allocated it), which we will have at - present. */ - tree fnf2_x - = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, - false, tf_warning_or_error); + finish_expr_stmt (c); - tree need_free_if = begin_if_stmt (); - fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x); - tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node); - finish_if_stmt_cond (cmp, need_free_if); + /* Argument copies ... */ while (!param_dtor_list->is_empty ()) { tree parm_id = param_dtor_list->pop (); tree a = coro_build_frame_access_expr (actor_frame, parm_id, false, tf_warning_or_error); if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error)) - add_stmt (dtor); + finish_expr_stmt (dtor); } + /* Here deallocate the frame (if we allocated it), which we will have at + present. */ + tree fnf2_x + = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id, + false, tf_warning_or_error); + tree need_free_if = begin_if_stmt (); + finish_if_stmt_cond (fnf2_x, need_free_if); + /* Build the frame DTOR. */ tree del_coro_fr = build_coroutine_frame_delete_expr (actor_fp, frame_size, promise_type, loc); finish_expr_stmt (del_coro_fr); finish_then_clause (need_free_if); - tree scope = IF_SCOPE (need_free_if); - IF_SCOPE (need_free_if) = NULL; - r = do_poplevel (scope); - add_stmt (r); + finish_if_stmt (need_free_if); - /* done. */ - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + /* Done. */ + finish_return_stmt (NULL_TREE); /* This is the suspend return point. */ - r = build_stmt (loc, LABEL_EXPR, ret_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, ret_label)); - r = build_stmt (loc, RETURN_EXPR, NULL); - suppress_warning (r); /* We don't want a warning about this. */ - r = maybe_cleanup_point_expr_void (r); - add_stmt (r); + finish_return_stmt (NULL_TREE); /* This is the 'continuation' return point. For such a case we have a coro handle (from the await_suspend() call) and we want handle.resume() to execute as a tailcall allowing arbitrary chaining of coroutines. */ - r = build_stmt (loc, LABEL_EXPR, continue_label); - add_stmt (r); + add_stmt (build_stmt (loc, LABEL_EXPR, continue_label)); /* Should have been set earlier by the coro_initialized code. */ gcc_assert (void_coro_handle_address); @@ -2678,19 +2787,25 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, we must tail call them. However, some targets do not support indirect tail calls to arbitrary callees. See PR94359. */ CALL_EXPR_TAILCALL (resume) = true; - resume = coro_build_cvt_void_expr_stmt (resume, loc); - add_stmt (resume); + finish_expr_stmt (resume); r = build_stmt (loc, RETURN_EXPR, NULL); gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r); add_stmt (r); + /* How to construct the handle for this coroutine from the frame address. */ + tree hfa_m = get_coroutine_from_address (orig); + /* Should have been set earlier by coro_promise_type_found_p. */ + gcc_assert (hfa_m); + tree handle_type = TREE_TYPE (get_coroutine_self_handle_proxy (orig)); + /* We've now rewritten the tree and added the initial and final co_awaits. Now pass over the tree and expand the co_awaits. */ - coro_aw_data data = {actor, actor_fp, resume_idx_var, NULL_TREE, - ash, del_promise_label, ret_label, - continue_label, restart_dispatch_label, continuation, 2}; + coro_aw_data data = {actor, actor_fp, resume_idx_var, i_a_r_c, + del_promise_label, ret_label, + continue_label, restart_dispatch_label, continuation, + handle_type, hfa_m, 2}; cp_walk_tree (&actor_body, await_statement_expander, &data, NULL); BIND_EXPR_BODY (actor_bind) = pop_stmt_list (actor_body); @@ -2882,8 +2997,8 @@ find_any_await (tree *stmt, int *dosub, void *d) if (TREE_CODE (*stmt) == CO_AWAIT_EXPR) { *dosub = 0; /* We don't need to consider this any further. */ - tree **p = (tree **) d; - *p = stmt; + if (d) + *(tree **)d = stmt; return *stmt; } return NULL_TREE; @@ -3133,7 +3248,9 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted, bool already_present = promoted->add (var); gcc_checking_assert (!already_present); tree inner = TARGET_EXPR_INITIAL (init); - gcc_checking_assert (TREE_CODE (inner) != COND_EXPR); + gcc_checking_assert + (TREE_CODE (inner) != COND_EXPR + || !cp_walk_tree (&inner, find_any_await, nullptr, nullptr)); init = cp_build_modify_expr (input_location, var, INIT_EXPR, init, tf_warning_or_error); /* Simplify for the case that we have an init containing the temp @@ -3438,7 +3555,8 @@ maybe_promote_temps (tree *stmt, void *d) return cp_walk_tree (stmt, register_awaits, d, &visited); } -/* Lightweight callback to determine two key factors: +/* Relatively lightweight callback to do initial assessment: + 0) Rewrite some await expressions. 1) If the statement/expression contains any await expressions. 2) If the statement/expression potentially requires a re-write to handle TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion @@ -3455,6 +3573,39 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d) switch (TREE_CODE (*stmt)) { default: return NULL_TREE; + case CALL_EXPR: + { + tree fn = cp_get_callee_fndecl_nofold (*stmt); + /* Special-cases where we want to re-write await expressions to some + other value before they are otherwise processed. */ + if (fn && DECL_IS_BUILTIN_CONSTANT_P (fn)) + { + gcc_checking_assert (call_expr_nargs (*stmt) == 1); + tree expr = CALL_EXPR_ARG (*stmt, 0); + if (cp_walk_tree (&expr, find_any_await, nullptr, NULL)) + { + if (TREE_CONSTANT (maybe_constant_value (expr))) + *stmt = integer_one_node; + else + *stmt = integer_zero_node; + } + *do_subtree = 0; + } + else if (!fn && CALL_EXPR_IFN (*stmt) == IFN_ASSUME) + { + tree expr = CALL_EXPR_ARG (*stmt, 0); + if (TREE_SIDE_EFFECTS (expr)) + { + location_t loc_e = cp_expr_location (expr); + location_t loc_s = cp_expr_location (*stmt); + location_t loc_n = make_location (loc_e, loc_s, loc_s); + warning_at (loc_n, OPT_Wattributes,"assumption ignored" + " because it contains an await-expression"); + *stmt = build_empty_stmt (loc_n); + } + } + } + break; case CO_YIELD_EXPR: /* co_yield is syntactic sugar, re-write it to co_await. */ *stmt = TREE_OPERAND (*stmt, 1); @@ -4045,12 +4196,14 @@ rewrite_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) } /* Build up a set of info that determines how each param copy will be - handled. */ + handled. We store this in a hash map so that we can access it from + a tree walk callback that re-writes the original parameters to their + copies. */ -static void -analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses) +void +cp_coroutine_transform::analyze_fn_parms () { - if (!DECL_ARGUMENTS (orig)) + if (!DECL_ARGUMENTS (orig_fn_decl)) return; /* Build a hash map with an entry for each param. @@ -4060,19 +4213,19 @@ analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses) Then a tree list of the uses. The second two entries start out empty - and only get populated when we see uses. */ - bool lambda_p = LAMBDA_FUNCTION_P (orig); + bool lambda_p = LAMBDA_FUNCTION_P (orig_fn_decl); /* Count the param copies from 1 as per the std. */ unsigned parm_num = 1; - for (tree arg = DECL_ARGUMENTS (orig); arg != NULL; + for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL; ++parm_num, arg = DECL_CHAIN (arg)) { bool existed; - param_info &parm = param_uses->get_or_insert (arg, &existed); + param_info &parm = param_uses.get_or_insert (arg, &existed); gcc_checking_assert (!existed); parm.body_uses = NULL; tree actual_type = TREE_TYPE (arg); - actual_type = complete_type_or_else (actual_type, orig); + actual_type = complete_type_or_else (actual_type, orig_fn_decl); if (actual_type == NULL_TREE) actual_type = error_mark_node; parm.orig_type = actual_type; @@ -4106,17 +4259,7 @@ analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses) } parm.field_id = name; if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type)) - { - char *buf = xasprintf ("_Coro_q%u_%s_live", parm_num, - DECL_NAME (arg) ? IDENTIFIER_POINTER (name) - : "__unnamed"); - parm.guard_var - = coro_build_artificial_var (UNKNOWN_LOCATION, get_identifier (buf), - boolean_type_node, orig, - boolean_false_node); - free (buf); - parm.trivial_dtor = false; - } + parm.trivial_dtor = false; else parm.trivial_dtor = true; } @@ -4307,8 +4450,7 @@ cp_coroutine_transform::wrap_original_function_body () { /* Avoid the code here attaching a location that makes the debugger jump. */ iloc_sentinel stable_input_loc (fn_start); - location_t loc = UNKNOWN_LOCATION; - input_location = loc; + location_t loc = fn_start; /* This will be our new outer scope. */ tree update_body @@ -4356,7 +4498,6 @@ cp_coroutine_transform::wrap_original_function_body () /* Wrap the function body in a try {} catch (...) {} block, if exceptions are enabled. */ tree var_list = NULL_TREE; - tree initial_await = build_init_or_final_await (fn_start, false); /* [stmt.return.coroutine] / 3 If p.return_void() is a valid expression, flowing off the end of a @@ -4395,16 +4536,6 @@ cp_coroutine_transform::wrap_original_function_body () var_list = promise; add_decl_expr (promise); - /* We need a handle to this coroutine, which is passed to every - await_suspend(). This was created on demand when parsing we now link it - into our scope. */ - var = get_coroutine_self_handle_proxy (orig_fn_decl); - DECL_CONTEXT (var) = orig_fn_decl; - DECL_SOURCE_LOCATION (var) = loc; - DECL_CHAIN (var) = var_list; - var_list = var; - add_decl_expr (var); - /* If we have function parms, then these will be copied to the coroutine frame as per [dcl.fct.def.coroutine] / 13. Here, we create a local (proxy) variable for each parm, since the original @@ -4448,27 +4579,44 @@ cp_coroutine_transform::wrap_original_function_body () var_list = resume_idx_var; add_decl_expr (resume_idx_var); + tree coro_frame_refcount + = coro_build_artificial_var (loc, coro_frame_refcount_id, + short_unsigned_type_node, orig_fn_decl, + NULL_TREE); + DECL_CHAIN (coro_frame_refcount) = var_list; + var_list = coro_frame_refcount; + add_decl_expr (coro_frame_refcount); + /* If the coroutine has a frame that needs to be freed, this will be set by the ramp. */ - var = coro_build_artificial_var (fn_start, coro_frame_needs_free_id, + var = coro_build_artificial_var (loc, coro_frame_needs_free_id, boolean_type_node, orig_fn_decl, NULL_TREE); DECL_CHAIN (var) = var_list; var_list = var; add_decl_expr (var); + /* We consider that the body has a use of the frame once we start to process + the initial suspend expression. (the use might be relinquished if we + encounter an exception before the body is finished). */ + tree body_use + = build2_loc (loc, PLUS_EXPR, short_unsigned_type_node, coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 1)); + body_use = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, body_use, + tf_warning_or_error); + finish_expr_stmt (body_use); if (flag_exceptions) { /* Build promise.unhandled_exception(); */ tree ueh = coro_build_promise_expression (orig_fn_decl, promise, coro_unhandled_exception_identifier, - fn_start, NULL, /*musthave=*/true); + loc, NULL, /*musthave=*/true); /* Create and initialize the initial-await-resume-called variable per [dcl.fct.def.coroutine] / 5.3. */ tree i_a_r_c = coro_build_artificial_var (loc, coro_frame_i_a_r_c_id, boolean_type_node, orig_fn_decl, - boolean_false_node); + NULL_TREE); DECL_CHAIN (i_a_r_c) = var_list; var_list = i_a_r_c; add_decl_expr (i_a_r_c); @@ -4476,34 +4624,28 @@ cp_coroutine_transform::wrap_original_function_body () tree tcb = build_stmt (loc, TRY_BLOCK, NULL_TREE, NULL_TREE); add_stmt (tcb); TRY_STMTS (tcb) = push_stmt_list (); - if (initial_await != error_mark_node) - { - /* Build a compound expression that sets the - initial-await-resume-called variable true and then calls the - initial suspend expression await resume. - In the case that the user decides to make the initial await - await_resume() return a value, we need to discard it and, it is - a reference type, look past the indirection. */ - if (INDIRECT_REF_P (initial_await)) - initial_await = TREE_OPERAND (initial_await, 0); - /* In the case that the initial_await returns a target expression - we might need to look through that to update the await expr. */ - tree iaw = initial_await; - if (TREE_CODE (iaw) == TARGET_EXPR) - iaw = TARGET_EXPR_INITIAL (iaw); - gcc_checking_assert (TREE_CODE (iaw) == CO_AWAIT_EXPR); - tree vec = TREE_OPERAND (iaw, 3); - tree aw_r = TREE_VEC_ELT (vec, 2); - aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error); - tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c, - boolean_true_node); - aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error); - TREE_VEC_ELT (vec, 2) = aw_r; - } + /* We need a new scope to handle the cleanup for the ramp use that is + needed for exceptions. */ + tree except_scope = begin_compound_stmt (0); + current_binding_level->artificial = 1; + tree release + = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node, + coro_frame_refcount, build_int_cst (short_unsigned_type_node, 1)); + release = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, + release, tf_warning_or_error); + /* Once we pass the initial await resume, the cleanup rules on exception + change so that the responsibility lies with the caller. */ + release = build3 (COND_EXPR, void_type_node, i_a_r_c, + build_empty_stmt (loc), release); + push_cleanup (NULL_TREE, release, /*ehonly*/true); /* Add the initial await to the start of the user-authored function. */ finish_expr_stmt (initial_await); + /* End the scope that handles the remove of frame-use on exception. */ + finish_compound_stmt (except_scope); + /* Append the original function body. */ add_stmt (coroutine_body); + if (return_void) add_stmt (return_void); TRY_STMTS (tcb) = pop_stmt_list (TRY_STMTS (tcb)); @@ -4548,9 +4690,9 @@ cp_coroutine_transform::wrap_original_function_body () tree ueh_meth = lookup_promise_method (orig_fn_decl, coro_unhandled_exception_identifier, - fn_start, /*musthave=*/false); + loc, /*musthave=*/false); if (!ueh_meth || ueh_meth == error_mark_node) - warning_at (fn_start, 0, "no member named %qE in %qT", + warning_at (loc, 0, "no member named %qE in %qT", coro_unhandled_exception_identifier, get_coroutine_promise_type (orig_fn_decl)); } @@ -4563,6 +4705,10 @@ cp_coroutine_transform::wrap_original_function_body () add_stmt (return_void); } + /* We are now doing actions associated with the end of the function, so + point to the closing brace. */ + input_location = loc = fn_end; + /* co_return branches to the final_suspend label, so declare that now. */ fs_label = create_named_label_with_ctx (loc, "final.suspend", NULL_TREE); @@ -4574,7 +4720,8 @@ cp_coroutine_transform::wrap_original_function_body () zero_resume = build2_loc (loc, MODIFY_EXPR, act_des_fn_ptr_type, resume_fn_ptr, zero_resume); finish_expr_stmt (zero_resume); - finish_expr_stmt (build_init_or_final_await (fn_start, true)); + finish_expr_stmt (final_await); + BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body)); BIND_EXPR_VARS (update_body) = nreverse (var_list); BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body); @@ -4883,47 +5030,6 @@ cp_coroutine_transform::build_ramp_function () coro_fp = pushdecl (coro_fp); add_decl_expr (coro_fp); - tree coro_promise_live = NULL_TREE; - tree coro_gro_live = NULL_TREE; - if (flag_exceptions) - { - /* Signal that we need to clean up the promise object on exception. */ - coro_promise_live - = coro_build_and_push_artificial_var (loc, "_Coro_promise_live", - boolean_type_node, orig_fn_decl, - boolean_false_node); - - /* When the get-return-object is in the RETURN slot, we need to arrange - for cleanup on exception. */ - coro_gro_live - = coro_build_and_push_artificial_var (loc, "_Coro_gro_live", - boolean_type_node, orig_fn_decl, - boolean_false_node); - - /* To signal that we need to cleanup copied function args. */ - if (DECL_ARGUMENTS (orig_fn_decl)) - for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL; - arg = DECL_CHAIN (arg)) - { - param_info *parm_i = param_uses.get (arg); - if (parm_i->trivial_dtor) - continue; - parm_i->guard_var = pushdecl (parm_i->guard_var); - add_decl_expr (parm_i->guard_var); - } - } - - /* deref the frame pointer, to use in member access code. */ - tree deref_fp - = cp_build_indirect_ref (loc, coro_fp, RO_UNARY_STAR, - tf_warning_or_error); - tree frame_needs_free - = coro_build_and_push_artificial_var_with_dve (loc, - coro_frame_needs_free_id, - boolean_type_node, - orig_fn_decl, NULL_TREE, - deref_fp); - /* Build the frame. */ /* The CO_FRAME internal function is a mechanism to allow the middle end @@ -4967,37 +5073,35 @@ cp_coroutine_transform::build_ramp_function () finish_if_stmt (if_stmt); } + /* Dereference the frame pointer, to use in member access code. */ + tree deref_fp + = cp_build_indirect_ref (loc, coro_fp, RO_UNARY_STAR, tf_warning_or_error); + /* For now, once allocation has succeeded we always assume that this needs destruction, there's no impl. for frame allocation elision. */ - r = cp_build_init_expr (frame_needs_free, boolean_true_node); - finish_expr_stmt (r); - - /* Set up the promise. */ - tree p - = coro_build_and_push_artificial_var_with_dve (loc, coro_promise_id, - promise_type, orig_fn_decl, - NULL_TREE, deref_fp); + tree frame_needs_free + = coro_build_and_push_artificial_var_with_dve (loc, + coro_frame_needs_free_id, + boolean_type_node, + orig_fn_decl, + boolean_true_node, + deref_fp); + /* Although it appears to be unused here the frame entry is needed and we + just set it true. */ + TREE_USED (frame_needs_free) = true; - /* Up to now any exception thrown will propagate directly to the caller. - This is OK since the only source of such exceptions would be in allocation - of the coroutine frame, and therefore the ramp will not have initialized - any further state. From here, we will track state that needs explicit - destruction in the case that promise or g.r.o setup fails or an exception - is thrown from the initial suspend expression. */ - tree ramp_try_block = NULL_TREE; - tree ramp_try_stmts = NULL_TREE; - tree iarc_x = NULL_TREE; - if (flag_exceptions) - { - iarc_x - = coro_build_and_push_artificial_var_with_dve (loc, - coro_frame_i_a_r_c_id, - boolean_type_node, - orig_fn_decl, NULL_TREE, - deref_fp); - ramp_try_block = begin_try_block (); - ramp_try_stmts = begin_compound_stmt (BCS_TRY_BLOCK); - } + tree coro_frame_refcount + = coro_build_and_push_artificial_var_with_dve (loc, coro_frame_refcount_id, + short_unsigned_type_node, + orig_fn_decl, NULL_TREE, + deref_fp); + /* Cleanup if both the ramp and the body have finished. */ + tree cond + = build2_loc (loc, EQ_EXPR, short_unsigned_type_node, coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 0)); + r = build3 (COND_EXPR, void_type_node, cond, delete_frame_call, + build_empty_stmt (loc)); + push_cleanup (coro_fp, r, /*eh_only*/false); /* Put the resumer and destroyer functions in. */ @@ -5069,24 +5173,34 @@ cp_coroutine_transform::build_ramp_function () tf_warning_or_error); } finish_expr_stmt (r); + + /* Arrange for parm copies to be cleaned up when an exception is + thrown before initial await resume. */ if (!parm.trivial_dtor) { - param_dtor_list.safe_push (parm.field_id); - /* Cleanup this frame copy on exception. */ parm.fr_copy_dtor = cxx_maybe_build_cleanup (fld_idx, tf_warning_or_error); - if (flag_exceptions) + if (parm.fr_copy_dtor && parm.fr_copy_dtor != error_mark_node) { - /* This var is now live. */ - r = build_modify_expr (loc, parm.guard_var, - boolean_type_node, INIT_EXPR, loc, - boolean_true_node, boolean_type_node); - finish_expr_stmt (r); + param_dtor_list.safe_push (parm.field_id); + cond + = build2_loc (loc, EQ_EXPR, short_unsigned_type_node, + coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 0)); + r = build3_loc (loc, COND_EXPR, void_type_node, cond, + parm.fr_copy_dtor, build_empty_stmt (loc)); + push_cleanup (fld_idx, r, /*eh_only*/false); } } } } + /* Set up the promise. */ + tree p + = coro_build_and_push_artificial_var_with_dve (loc, coro_promise_id, + promise_type, orig_fn_decl, + NULL_TREE, deref_fp); + if (type_build_ctor_call (promise_type)) { /* Construct the promise object [dcl.fct.def.coroutine] / 5.7. @@ -5120,11 +5234,16 @@ cp_coroutine_transform::build_ramp_function () finish_expr_stmt (r); } - tree promise_dtor = cxx_maybe_build_cleanup (p, tf_warning_or_error);; - if (flag_exceptions && promise_dtor) + tree promise_dtor = cxx_maybe_build_cleanup (p, tf_warning_or_error); + /* If the promise is live, then run its dtor if that's available. */ + if (promise_dtor && promise_dtor != error_mark_node) { - r = cp_build_init_expr (coro_promise_live, boolean_true_node); - finish_expr_stmt (r); + cond = build2_loc (loc, EQ_EXPR, short_unsigned_type_node, + coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 0)); + r = build3 (COND_EXPR, void_type_node, cond, promise_dtor, + build_empty_stmt (loc)); + push_cleanup (p, r, /*eh_only*/false); } tree get_ro @@ -5139,8 +5258,11 @@ cp_coroutine_transform::build_ramp_function () /* Check for a bad get return object type. [dcl.fct.def.coroutine] / 7 requires: The expression promise.get_return_object() is used to initialize the - returned reference or prvalue result object ... */ - tree gro_type = TREE_TYPE (get_ro); + returned reference or prvalue result object ... + When we use a local to hold this, it is decltype(auto). */ + tree gro_type + = finish_decltype_type (get_ro, /*id_expression_or_member_access_p*/false, + tf_warning_or_error); if (VOID_TYPE_P (gro_type) && !void_ramp_p) { error_at (fn_start, "no viable conversion from %<void%> provided by" @@ -5153,169 +5275,62 @@ cp_coroutine_transform::build_ramp_function () (loc, coro_resume_index_id, short_unsigned_type_node, orig_fn_decl, build_zero_cst (short_unsigned_type_node), deref_fp); - if (flag_exceptions && iarc_x) - { - r = cp_build_init_expr (iarc_x, boolean_false_node); - finish_expr_stmt (r); - } - - /* Used for return objects in the RESULT slot. */ - tree ret_val_dtor = NULL_TREE; - tree retval = NULL_TREE; + /* We must manage the cleanups ourselves, with the exception of the g_r_o, + because the responsibility for them changes after the initial suspend. + However, any use of cxx_maybe_build_cleanup () in preceding code can + set the throwing_cleanup flag. */ + cp_function_chain->throwing_cleanup = false; /* [dcl.fct.def.coroutine] / 7 The expression promise.get_return_object() is used to initialize the glvalue result or prvalue result object of a call to a coroutine. */ - /* We must manage the cleanups ourselves, because the responsibility for - them changes after the initial suspend. However, any use of - cxx_maybe_build_cleanup () can set the throwing_cleanup flag. */ - cp_function_chain->throwing_cleanup = false; + tree coro_gro = NULL_TREE; if (void_ramp_p) /* We still want to call the method, even if the result is unused. */ - r = get_ro; + finish_expr_stmt (get_ro); else { - /* The initial section of finish_return_expr (). */ - bool no_warning; - bool dangling; - /* Without a relevant location, bad conversions in check_return_expr - result in unusable diagnostics, since there is not even a mention - of the relevant function. Here we carry out the first part of - finish_return_expr(). */ - input_location = fn_start; - r = check_return_expr (get_ro, &no_warning, &dangling); - input_location = UNKNOWN_LOCATION; - gcc_checking_assert (!dangling); - /* Check for bad things. */ - if (!r || r == error_mark_node) - return false; - if (!aggregate_value_p (fn_return_type, orig_fn_decl) - && TREE_CODE (r) == INIT_EXPR) - { - /* If fn_return_type doesn't need to be returned in memory, normally - gimplify_return_expr redirects the INIT_EXPR to a temporary. But - r isn't wrapped in the RETURN_EXPR, so we need to do the - redirection here as well. See PR118874. */ - tree temp = create_temporary_var (fn_return_type); - add_decl_expr (temp); - retval = copy_node (r); - TREE_OPERAND (r, 0) = temp; - TREE_OPERAND (retval, 1) = temp; - } - else - retval = DECL_RESULT (orig_fn_decl); - } - - finish_expr_stmt (r); + /* Per CWG2563, we keep the result of promise.get_return_object () in + a temp which is then used to intialize the return object, including + NVRO. */ - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (fn_return_type)) - /* If some part of the initalization code (prior to the await_resume - of the initial suspend expression), then we need to clean up the - return value. */ - ret_val_dtor = cxx_maybe_build_cleanup (DECL_RESULT (orig_fn_decl), - tf_warning_or_error); + /* Temporary var to hold the g_r_o across the function body. */ + coro_gro + = coro_build_and_push_artificial_var (loc, "_Coro_gro", gro_type, + orig_fn_decl, NULL_TREE); - /* If we have a live g.r.o in the return slot, then signal this for exception - cleanup. */ - if (flag_exceptions && ret_val_dtor) - { - r = cp_build_init_expr (coro_gro_live, boolean_true_node); + r = cp_build_init_expr (coro_gro, STRIP_REFERENCE_REF (get_ro)); finish_expr_stmt (r); + tree coro_gro_cleanup + = cxx_maybe_build_cleanup (coro_gro, tf_warning_or_error); + if (coro_gro_cleanup) + push_cleanup (coro_gro, coro_gro_cleanup, /*eh_only*/false); } - /* Start the coroutine body. */ + /* Start the coroutine body, we now have a use of the frame... */ + r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, + build_int_cst (short_unsigned_type_node, 1), + tf_warning_or_error); + finish_expr_stmt (r); + /* ... but when we finish we want to release that, and we want to do that + before any of the other cleanups run. */ + tree released + = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node, coro_frame_refcount, + build_int_cst (short_unsigned_type_node, 1)); + released = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released, + tf_warning_or_error); + push_cleanup (NULL_TREE, released, /*eh_only*/false); + r = build_call_expr_loc (fn_start, resumer, 1, coro_fp); finish_expr_stmt (r); /* The ramp is done, we just need the return statement, which we build from the return object we constructed before we called the actor. */ - r = retval; - - /* The reminder of finish_return_expr (). */ - r = build_stmt (loc, RETURN_EXPR, r); - r = maybe_cleanup_point_expr_void (r); - r = add_stmt (r); + r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro); + finish_return_stmt (r); - if (flag_exceptions) - { - finish_compound_stmt (ramp_try_stmts); - finish_try_block (ramp_try_block); - tree handler = begin_handler (); - finish_handler_parms (NULL_TREE, handler); /* catch (...) */ - - /* If we have a live G.R.O in the return slot, then run its DTOR. */ - if (ret_val_dtor && ret_val_dtor != error_mark_node) - { - tree gro_d_if = begin_if_stmt (); - finish_if_stmt_cond (coro_gro_live, gro_d_if); - finish_expr_stmt (ret_val_dtor); - finish_then_clause (gro_d_if); - finish_if_stmt (gro_d_if); - } - - /* Before initial resume is called, the responsibility for cleanup on - exception falls to the ramp. After that, the coroutine body code - should do the cleanup. This is signalled by the flag - 'initial_await_resume_called'. */ - - tree not_iarc - = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, iarc_x); - tree cleanup_if = begin_if_stmt (); - finish_if_stmt_cond (not_iarc, cleanup_if); - /* If the promise is live, then run its dtor if that's available. */ - if (promise_dtor && promise_dtor != error_mark_node) - { - tree promise_d_if = begin_if_stmt (); - finish_if_stmt_cond (coro_promise_live, promise_d_if); - finish_expr_stmt (promise_dtor); - finish_then_clause (promise_d_if); - finish_if_stmt (promise_d_if); - } - - /* Clean up any frame copies of parms with non-trivial dtors. - Do this in reverse order from their creation. */ - auto_vec<param_info *> worklist; - if (DECL_ARGUMENTS (orig_fn_decl)) - for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL; - arg = DECL_CHAIN (arg)) - { - param_info *parm_i = param_uses.get (arg); - if (parm_i->trivial_dtor) - continue; - worklist.safe_push (parm_i); - } - while (!worklist.is_empty ()) - { - param_info *parm_i = worklist.pop (); - if (parm_i->fr_copy_dtor && parm_i->fr_copy_dtor != error_mark_node) - { - tree dtor_if = begin_if_stmt (); - finish_if_stmt_cond (parm_i->guard_var, dtor_if); - finish_expr_stmt (parm_i->fr_copy_dtor); - finish_then_clause (dtor_if); - finish_if_stmt (dtor_if); - } - } - - /* No delete the frame if required. */ - tree fnf_if = begin_if_stmt (); - finish_if_stmt_cond (frame_needs_free, fnf_if); - finish_expr_stmt (delete_frame_call); - finish_then_clause (fnf_if); - finish_if_stmt (fnf_if); - - /* Finished cleanups conditional on "initial resume is not called". */ - finish_then_clause (cleanup_if); - finish_if_stmt (cleanup_if); - - tree rethrow = build_throw (loc, NULL_TREE, tf_warning_or_error); - suppress_warning (rethrow); - finish_expr_stmt (rethrow); - finish_handler (handler); - finish_handler_sequence (ramp_try_block); - } finish_compound_stmt (ramp_fnbody); return true; } @@ -5346,9 +5361,10 @@ cp_coroutine_transform::cp_coroutine_transform (tree _orig_fn, bool _inl) } /* We don't have the locus of the opening brace - it's filled in later (and - there doesn't really seem to be any easy way to get at it). - The closing brace is assumed to be input_location. */ + there doesn't really seem to be any easy way to get at it). */ fn_start = DECL_SOURCE_LOCATION (orig_fn_decl); + /* The closing brace is assumed to be input_location. */ + fn_end = input_location; /* Build types we need. */ tree fr_name = get_fn_local_identifier (orig_fn_decl, "Frame"); @@ -5389,7 +5405,6 @@ cp_coroutine_transform::~cp_coroutine_transform () bool _Coro_frame_needs_free; free the coro frame mem if set. bool _Coro_i_a_r_c; [dcl.fct.def.coroutine] / 5.3 short _Coro_resume_index; - handle_type _Coro_self_handle; parameter copies (were required). local variables saved (including awaitables) (maybe) trailing space. @@ -5416,7 +5431,7 @@ cp_coroutine_transform::apply_transforms () /* Collect information on the original function params and their use in the function body. */ - analyze_fn_parms (orig_fn_decl, ¶m_uses); + analyze_fn_parms (); /* Declare the actor and destroyer functions, the following code needs to see these. */ @@ -5427,6 +5442,16 @@ cp_coroutine_transform::apply_transforms () = coro_build_actor_or_destroy_function (orig_fn_decl, act_des_fn_type, frame_ptr_type, false); + /* Avoid repeating diagnostics about promise or awaiter fails. */ + if (!seen_error ()) + { + iloc_sentinel stable_input_loc (fn_start); + initial_await = build_init_or_final_await (fn_start, false); + input_location = fn_end; + if (initial_await && initial_await != error_mark_node) + final_await = build_init_or_final_await (fn_end, true); + } + /* Transform the function body as per [dcl.fct.def.coroutine] / 5. */ wrap_original_function_body (); diff --git a/gcc/cp/coroutines.h b/gcc/cp/coroutines.h index d13bea0..fcc4645 100644 --- a/gcc/cp/coroutines.h +++ b/gcc/cp/coroutines.h @@ -9,7 +9,6 @@ struct param_info vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */ tree frame_type; /* The type used to represent this parm in the frame. */ tree orig_type; /* The original type of the parm (not as passed). */ - tree guard_var; /* If we need a DTOR on exception, this bool guards it. */ tree fr_copy_dtor; /* If we need a DTOR on exception, this is it. */ bool by_ref; /* Was passed by reference. */ bool pt_ref; /* Was a pointer to object. */ @@ -101,8 +100,8 @@ public: private: tree orig_fn_decl; /* The original function decl. */ - tree orig_fn_body = NULL_TREE; /* The original function body. */ location_t fn_start = UNKNOWN_LOCATION; + location_t fn_end = UNKNOWN_LOCATION; tree resumer = error_mark_node; tree destroyer = error_mark_node; tree coroutine_body = NULL_TREE; @@ -127,6 +126,10 @@ private: bool inline_p = false; bool valid_coroutine = false; + tree initial_await = error_mark_node; + tree final_await = error_mark_node; + + void analyze_fn_parms (); void wrap_original_function_body (); bool build_ramp_function (); }; diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 550cea29..ce69bd6 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1199,8 +1199,11 @@ cp_build_init_expr_for_ctor (tree call, tree init) tree s = build_fold_indirect_ref_loc (loc, a); init = cp_build_init_expr (s, init); if (return_this) - init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init, - fold_convert_loc (loc, TREE_TYPE (call), a)); + { + init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init, + fold_convert_loc (loc, TREE_TYPE (call), a)); + suppress_warning (init); + } return init; } @@ -1470,6 +1473,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) break; case TARGET_EXPR: + if (!flag_no_inline) + if (tree &init = TARGET_EXPR_INITIAL (stmt)) + { + tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt), + (data->flags & ff_mce_false + ? mce_false : mce_unknown)); + if (folded != init && TREE_CONSTANT (folded)) + init = folded; + } + + /* This needs to happen between the constexpr evaluation (which wants + pre-generic trees) and fold (which wants the cp_genericize_init + transformations). */ if (data->flags & ff_genericize) cp_genericize_target_expr (stmt_p); @@ -1478,12 +1494,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) cp_walk_tree (&init, cp_fold_r, data, NULL); cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL); *walk_subtrees = 0; - if (!flag_no_inline) - { - tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt)); - if (folded != init && TREE_CONSTANT (folded)) - init = folded; - } /* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in that case, strip it in favor of this one. */ if (TREE_CODE (init) == TARGET_EXPR) @@ -2804,6 +2814,12 @@ cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) } } +tree +cxx_omp_finish_mapper_clauses (tree clauses) +{ + return finish_omp_clauses (clauses, C_ORT_OMP); +} + /* Return true if DECL's DECL_VALUE_EXPR (if any) should be disregarded in OpenMP construct, because it is going to be remapped during OpenMP lowering. SHARED is true if DECL @@ -3338,19 +3354,13 @@ cp_fold (tree x, fold_flags_t flags) || id_equal (DECL_NAME (callee), "addressof") /* This addressof equivalent is used heavily in libstdc++. */ || id_equal (DECL_NAME (callee), "__addressof") + || id_equal (DECL_NAME (callee), "to_underlying") || id_equal (DECL_NAME (callee), "as_const"))) { r = CALL_EXPR_ARG (x, 0); - /* Check that the return and argument types are sane before - folding. */ - if (INDIRECT_TYPE_P (TREE_TYPE (x)) - && INDIRECT_TYPE_P (TREE_TYPE (r))) - { - if (!same_type_p (TREE_TYPE (x), TREE_TYPE (r))) - r = build_nop (TREE_TYPE (x), r); - x = cp_fold (r, flags); - break; - } + r = build_nop (TREE_TYPE (x), r); + x = cp_fold (r, flags); + break; } int sv = optimize, nw = sv; @@ -3442,7 +3452,9 @@ cp_fold (tree x, fold_flags_t flags) Do constexpr expansion of expressions where the call itself is not constant, but the call followed by an INDIRECT_REF is. */ if (callee && DECL_DECLARED_CONSTEXPR_P (callee) - && !flag_no_inline) + && (!flag_no_inline + || lookup_attribute ("always_inline", + DECL_ATTRIBUTES (callee)))) { mce_value manifestly_const_eval = mce_unknown; if (flags & ff_mce_false) @@ -3875,7 +3887,6 @@ struct source_location_table_entry_hash static GTY(()) hash_table <source_location_table_entry_hash> *source_location_table; -static GTY(()) unsigned int source_location_id; /* Fold the __builtin_source_location () call T. */ @@ -3908,9 +3919,7 @@ fold_builtin_source_location (const_tree t) var = entryp->var; else { - char tmp_name[32]; - ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++); - var = build_decl (loc, VAR_DECL, get_identifier (tmp_name), + var = build_decl (loc, VAR_DECL, generate_internal_label ("Lsrc_loc"), source_location_impl); TREE_STATIC (var) = 1; TREE_PUBLIC (var) = 0; diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 8336d0b..7665b94 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -614,6 +614,8 @@ cp_register_dumps (gcc::dump_manager *dumps) (".raw", "lang-raw", "lang-raw", DK_lang, OPTGROUP_NONE, false); coro_dump_id = dumps->dump_register (".coro", "lang-coro", "lang-coro", DK_lang, OPTGROUP_NONE, false); + tinst_dump_id = dumps->dump_register + (".tinst", "lang-tinst", "lang-tinst", DK_lang, OPTGROUP_NONE, false); } void diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 13fb80c..ff35428 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -190,6 +190,15 @@ static const scoped_attribute_specs *const cp_objcp_attribute_table[] = #define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor #undef LANG_HOOKS_OMP_FINISH_CLAUSE #define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause +#undef LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES +#define LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES cxx_omp_finish_mapper_clauses +#undef LANG_HOOKS_OMP_MAPPER_LOOKUP +#define LANG_HOOKS_OMP_MAPPER_LOOKUP cxx_omp_mapper_lookup +#undef LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE +#define LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE \ + cxx_omp_extract_mapper_directive +#undef LANG_HOOKS_OMP_MAP_ARRAY_SECTION +#define LANG_HOOKS_OMP_MAP_ARRAY_SECTION cxx_omp_map_array_section #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference #undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def index 6aaca13..e71b28c 100644 --- a/gcc/cp/cp-trait.def +++ b/gcc/cp/cp-trait.def @@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) DEFTRAIT_EXPR (IS_CONST, "__is_const", 1) DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) +DEFTRAIT_EXPR (IS_DESTRUCTIBLE, "__is_destructible", 1) DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1) DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1) DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1) @@ -84,6 +85,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1) DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) +DEFTRAIT_EXPR (IS_NOTHROW_DESTRUCTIBLE, "__is_nothrow_destructible", 1) DEFTRAIT_EXPR (IS_NOTHROW_INVOCABLE, "__is_nothrow_invocable", -1) DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1) DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) @@ -98,6 +100,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1) DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2) DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1) DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1) +DEFTRAIT_EXPR (IS_TRIVIALLY_DESTRUCTIBLE, "__is_trivially_destructible", 1) DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1) DEFTRAIT_EXPR (IS_UNION, "__is_union", 1) DEFTRAIT_EXPR (IS_VIRTUAL_BASE_OF, "__builtin_is_virtual_base_of", 2) @@ -111,6 +114,7 @@ DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1) DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1) DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) +DEFTRAIT_EXPR (TYPE_ORDER, "__builtin_type_order", 2) DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1) DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 927f51b..1b893e2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2206,6 +2206,8 @@ struct GTY(()) language_function { BOOL_BITFIELD invalid_constexpr : 1; BOOL_BITFIELD throwing_cleanup : 1; + /* True if we gave any errors in this function. */ + BOOL_BITFIELD erroneous : 1; hash_table<named_label_hash> *x_named_labels; @@ -2489,6 +2491,7 @@ struct GTY(()) lang_type { unsigned unique_obj_representations_set : 1; bool erroneous : 1; bool non_pod_aggregate : 1; + bool non_aggregate_pod : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -2497,7 +2500,7 @@ struct GTY(()) lang_type { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 3; + unsigned dummy : 2; tree primary_base; vec<tree_pair_s, va_gc> *vcall_indices; @@ -2511,12 +2514,16 @@ struct GTY(()) lang_type { tree key_method; tree decl_list; tree befriending_classes; - /* In a RECORD_TYPE, information specific to Objective-C++, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; /* FIXME reuse another field? */ tree lambda_expr; + union maybe_objc_info { + /* If not c_dialect_objc, this part is not even allocated. */ + char GTY((tag ("0"))) non_objc; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree GTY((tag ("1"))) objc_info; + } GTY ((desc ("c_dialect_objc ()"))) info; }; /* We used to have a variant type for lang_type. Keep the name of the @@ -2824,6 +2831,11 @@ struct GTY(()) lang_type { with a hash_set only filled in when abi_version_crosses (17). */ #define CLASSTYPE_NON_POD_AGGREGATE(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->non_pod_aggregate) + +/* True if this class is layout-POD though it's not an aggregate in C++20 and + above (c++/120012). This could also be a hash_set. */ +#define CLASSTYPE_NON_AGGREGATE_POD(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->non_aggregate_pod) /* Additional macros for inheritance information. */ @@ -2967,7 +2979,10 @@ struct GTY(()) lang_decl_base { unsigned module_keyed_decls_p : 1; /* has keys, applies to all decls */ - /* 11 spare bits. */ + /* VAR_DECL being used to represent an OpenMP declared mapper. */ + unsigned omp_declare_mapper_p : 1; + + /* 10 spare bits. */ }; /* True for DECL codes which have template info and access. */ @@ -4522,6 +4537,11 @@ get_vec_init_expr (tree t) #define DECL_OMP_DECLARE_REDUCTION_P(NODE) \ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p) +/* Nonzero if NODE is an artificial FUNCTION_DECL for + #pragma omp declare mapper. */ +#define DECL_OMP_DECLARE_MAPPER_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.omp_declare_mapper_p) + /* Nonzero if DECL has been declared threadprivate by #pragma omp threadprivate. */ #define CP_DECL_THREADPRIVATE_P(DECL) \ @@ -5514,6 +5534,10 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn) #define DECL_RAMP_FN(NODE) \ (coro_get_ramp_function (NODE)) +/* For a FUNCTION_DECL this is true if it is a coroutine ramp. */ +#define DECL_RAMP_P(NODE) \ + DECL_COROUTINE_P (NODE) && !DECL_RAMP_FN (NODE) + /* True for an OMP_ATOMIC that has dependent parameters. These are stored as an expr in operand 1, and integer_zero_node or clauses in operand 0. */ #define OMP_ATOMIC_DEPENDENT_P(NODE) \ @@ -6753,8 +6777,14 @@ struct GTY((chain_next ("%h.next"))) tinst_level { /* The location where the template is instantiated. */ location_t locus; - /* errorcount + sorrycount when we pushed this level. */ - unsigned short errors; + /* errorcount + sorrycount when we pushed this level. If the value + overflows, it will always seem like we currently have more errors, so we + will limit template recursion even from non-erroneous templates. In a TU + with over 32k errors, that's fine. */ + unsigned short errors : 15; + + /* set in pop_tinst_level if there have been errors since we pushed. */ + bool had_errors : 1; /* Count references to this object. If refcount reaches refcount_infinity value, we don't increment or decrement the @@ -6808,6 +6838,7 @@ extern int class_dump_id; extern int module_dump_id; extern int raw_dump_id; extern int coro_dump_id; +extern int tinst_dump_id; /* Whether the current context is manifestly constant-evaluated. Used by the constexpr machinery to control folding of @@ -7042,6 +7073,7 @@ extern tree in_class_defaulted_default_constructor (tree); extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_non_user_provided_default_constructor (tree); +extern bool type_has_converting_constructor (tree); extern bool vbase_has_user_provided_move_assign (tree); extern tree default_init_uninitialized_part (tree); extern bool trivial_default_constructor_is_constexpr (tree); @@ -7072,6 +7104,7 @@ extern void adjust_clone_args (tree); extern void deduce_noexcept_on_destructor (tree); extern bool uniquely_derived_from_p (tree, tree); extern bool publicly_uniquely_derived_p (tree, tree); +extern bool publicly_virtually_derived_p (tree, tree); extern tree common_enclosing_class (tree, tree); /* in cvt.cc */ @@ -7307,6 +7340,29 @@ extern void cp_check_const_attributes (tree); extern void maybe_propagate_warmth_attributes (tree, tree); /* in error.cc */ +/* A class for pretty-printing to -flang-dump-XXX files. Used like + + if (cxx_dump_pretty_printer pp {foo_dump_id}) + { + pp_printf (&pp, ...); + } + + If the dump is enabled, the pretty printer will open the dump file and + attach to it, and flush and close the file on destruction. */ + +class cxx_dump_pretty_printer: public pretty_printer +{ + int phase; + FILE *outf; + dump_flags_t flags; + +public: + cxx_dump_pretty_printer (int phase); + operator bool() { return outf != nullptr; } + bool has_flag (dump_flags_t f) { return (flags & f); } + ~cxx_dump_pretty_printer (); +}; + extern const char *type_as_string (tree, int); extern const char *type_as_string_translate (tree, int); extern const char *decl_as_string (tree, int); @@ -7502,6 +7558,8 @@ extern bool ctor_omit_inherited_parms (tree); extern tree locate_ctor (tree); extern tree implicitly_declare_fn (special_function_kind, tree, bool, tree, tree); +extern tree type_order_value (tree, tree); + /* In module.cc */ class module_state; /* Forward declare. */ inline bool modules_p () { return flag_modules != 0; } @@ -7618,7 +7676,6 @@ extern void cp_finish_omp_range_for (tree, tree); extern bool cp_maybe_parse_omp_decl (tree, tree); extern bool parsing_nsdmi (void); extern bool parsing_function_declarator (); -extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); extern location_t defparse_location (tree); extern void maybe_show_extern_c_location (void); @@ -7759,6 +7816,7 @@ extern bool type_dependent_expression_p_push (tree); extern bool value_dependent_expression_p (tree); extern bool instantiation_dependent_uneval_expression_p (tree); extern bool any_value_dependent_elements_p (const_tree); +extern bool dependent_template_arg_p (tree); extern bool dependent_omp_for_p (tree, tree, tree, tree, tree); extern tree resolve_typename_type (tree, bool); extern tree template_for_substitution (tree); @@ -7906,6 +7964,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t); extern bool perform_or_defer_access_check (tree, tree, tree, tsubst_flags_t, access_failure_info *afi = NULL); +extern tree maybe_convert_cond (tree); /* RAII sentinel to ensures that deferred access checks are popped before a function returns. */ @@ -8054,11 +8113,14 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool, extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree, tree); extern tree omp_reduction_id (enum tree_code, tree, tree); +extern tree omp_mapper_id (tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); extern bool cp_check_omp_declare_reduction (tree); +extern bool cp_check_omp_declare_mapper (tree); extern void finish_omp_declare_simd_methods (tree); extern tree cp_finish_omp_init_prefer_type (tree); extern tree finish_omp_clauses (tree, enum c_omp_region_type); +extern tree omp_instantiate_mappers (tree); extern tree push_omp_privatization_clauses (bool); extern void pop_omp_privatization_clauses (tree); extern void save_omp_privatization_clauses (vec<tree> &); @@ -8654,6 +8716,10 @@ extern tree cxx_omp_clause_copy_ctor (tree, tree, tree); extern tree cxx_omp_clause_assign_op (tree, tree, tree); extern tree cxx_omp_clause_dtor (tree, tree); extern void cxx_omp_finish_clause (tree, gimple_seq *, bool); +extern tree cxx_omp_finish_mapper_clauses (tree); +extern tree cxx_omp_mapper_lookup (tree, tree); +extern tree cxx_omp_extract_mapper_directive (tree); +extern tree cxx_omp_map_array_section (location_t, tree); extern bool cxx_omp_privatize_by_reference (const_tree); extern bool cxx_omp_disregard_value_expr (tree, bool); extern void cp_fold_function (tree); @@ -8780,7 +8846,8 @@ extern hashval_t iterative_hash_constraint (tree, hashval_t); extern hashval_t hash_atomic_constraint (tree); extern void diagnose_constraints (location_t, tree, tree); -extern void note_failed_type_completion_for_satisfaction (tree); +extern void note_failed_type_completion (tree, tsubst_flags_t); +extern location_t failed_completion_location (tree); /* in logic.cc */ extern bool subsumes (tree, tree); @@ -8837,6 +8904,7 @@ extern void cxx_constant_dtor (tree, tree); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE, mce_value = mce_unknown); extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_init (tree, tree, mce_value); extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, bool = false, tree = NULL_TREE); @@ -8847,7 +8915,7 @@ extern tree fold_non_dependent_init (tree, bool = false, tree = NULL_TREE); extern tree fold_simple (tree); extern tree fold_to_constant (tree); -extern bool reduced_constant_expression_p (tree); +extern bool reduced_constant_expression_p (tree, tree = NULL_TREE); extern bool is_instantiation_of_constexpr (tree); extern bool var_in_constexpr_fn (tree); extern bool var_in_maybe_constexpr_fn (tree); diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index cf301bd..5f24015 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "cp-tree.h" #include "cxx-pretty-print.h" #include "tree-pretty-print.h" -#include "make-unique.h" static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree); static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree); @@ -2954,5 +2953,5 @@ cxx_pretty_printer::cxx_pretty_printer () std::unique_ptr<pretty_printer> cxx_pretty_printer::clone () const { - return ::make_unique<cxx_pretty_printer> (*this); + return std::make_unique<cxx_pretty_printer> (*this); } diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4e97093..83c8e28 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -846,11 +846,9 @@ poplevel (int keep, int reverse, int functionbody) DECL_INITIAL (current_function_decl) = block ? block : subblocks; if (subblocks) { - if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) - { - if (BLOCK_SUBBLOCKS (subblocks)) - BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1; - } + if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl) + && BLOCK_SUBBLOCKS (subblocks)) + BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1; else BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1; } @@ -1313,7 +1311,15 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record) } if (record) - cgraph_node::record_function_versions (olddecl, newdecl); + { + /* Add the new version to the function version structure. */ + cgraph_node *fn_node = cgraph_node::get_create (olddecl); + cgraph_function_version_info *fn_v = fn_node->function_version (); + if (!fn_v) + fn_v = fn_node->insert_new_function_version (); + + cgraph_node::add_function_version (fn_v, newdecl); + } return true; } @@ -5339,6 +5345,8 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep) decl = pushdecl_outermost_localscope (decl); if (decl != error_mark_node) add_decl_expr (decl); + else + gcc_assert (seen_error ()); } else { @@ -6198,22 +6206,28 @@ start_decl (const cp_declarator *declarator, } if (current_function_decl && VAR_P (decl) - && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && maybe_constexpr_fn (current_function_decl) && cxx_dialect < cxx23) { bool ok = false; if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined %<thread_local%> in %qs function only " - "available with %<-std=c++23%> or %<-std=gnu++23%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); + { + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined %<thread_local%> in %qs function only " + "available with %<-std=c++23%> or %<-std=gnu++23%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + } else if (TREE_STATIC (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined %<static%> in %qs function only available " - "with %<-std=c++23%> or %<-std=gnu++23%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); + { + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined %<static%> in %qs function only available " + "with %<-std=c++23%> or %<-std=gnu++23%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + } else ok = true; if (!ok) @@ -7871,6 +7885,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups) } else if (!init && DECL_REALLY_EXTERN (decl)) ; + else if (flag_openmp + && VAR_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl) + && TREE_CODE (init) == OMP_DECLARE_MAPPER) + return NULL_TREE; else if (init || type_build_ctor_call (type) || TYPE_REF_P (type)) { @@ -8897,13 +8917,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, TREE_TYPE (decl) = error_mark_node; return; } + + /* Now that we have a type, try these again. */ + layout_decl (decl, 0); cp_apply_type_quals_to_decl (cp_type_quals (type), decl); /* Update the type of the corresponding TEMPLATE_DECL to match. */ - if (DECL_LANG_SPECIFIC (decl) - && DECL_TEMPLATE_INFO (decl) - && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) == decl) - TREE_TYPE (DECL_TI_TEMPLATE (decl)) = type; + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) + { + tree tmpl = template_for_substitution (decl); + if (DECL_TEMPLATE_RESULT (tmpl) == decl) + TREE_TYPE (tmpl) = type; + } } if (ensure_literal_type_for_constexpr_object (decl) == error_mark_node) @@ -9188,14 +9213,23 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, varpool_node::get_create (decl); } + if (flag_openmp + && VAR_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl) + && init) + { + gcc_assert (TREE_CODE (init) == OMP_DECLARE_MAPPER); + DECL_INITIAL (decl) = init; + } /* Convert the initializer to the type of DECL, if we have not already initialized DECL. */ - if (!DECL_INITIALIZED_P (decl) - /* If !DECL_EXTERNAL then DECL is being defined. In the - case of a static data member initialized inside the - class-specifier, there can be an initializer even if DECL - is *not* defined. */ - && (!DECL_EXTERNAL (decl) || init)) + else if (!DECL_INITIALIZED_P (decl) + /* If !DECL_EXTERNAL then DECL is being defined. In the + case of a static data member initialized inside the + class-specifier, there can be an initializer even if DECL + is *not* defined. */ + && (!DECL_EXTERNAL (decl) || init)) { cleanups = make_tree_vector (); init = check_initializer (decl, init, flags, &cleanups); @@ -11294,11 +11328,16 @@ grokfndecl (tree ctype, "cannot declare %<::main%> to be %qs", "consteval"); if (!publicp) error_at (location, "cannot declare %<::main%> to be static"); - if (current_lang_depth () != 0) + if (current_lang_name != lang_name_cplusplus) pedwarn (location, OPT_Wpedantic, "cannot declare %<::main%> with a" - " linkage specification"); + " linkage specification other than %<extern \"C++\"%>"); if (module_attach_p ()) - error_at (location, "cannot attach %<::main%> to a named module"); + { + auto_diagnostic_group adg; + error_at (location, "cannot attach %<::main%> to a named module"); + inform (location, "use %<extern \"C++\"%> to attach it to the " + "global module instead"); + } inlinep = 0; publicp = 1; } @@ -19304,6 +19343,19 @@ finish_function (bool inline_p) } } + if (FNDECL_USED_AUTO (fndecl) + && TREE_TYPE (fntype) != DECL_SAVED_AUTO_RETURN_TYPE (fndecl)) + if (location_t fcloc = failed_completion_location (fndecl)) + { + auto_diagnostic_group adg; + if (warning (OPT_Wsfinae_incomplete_, + "defining %qD, which previously failed to be deduced " + "in a SFINAE context", fndecl) + && warn_sfinae_incomplete == 1) + inform (fcloc, "here. Use %qs for a diagnostic at that point", + "-Wsfinae-incomplete=2"); + } + /* Remember that we were in class scope. */ if (current_class_name) ctype = current_class_type; @@ -19957,7 +20009,7 @@ require_deduced_type (tree decl, tsubst_flags_t complain) /* We probably already complained about deduction failure. */; else if (complain & tf_error) error ("use of %qD before deduction of %<auto%>", decl); - note_failed_type_completion_for_satisfaction (decl); + note_failed_type_completion (decl, complain); return false; } return true; diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 21156f1..2bbc618 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -3160,7 +3160,9 @@ determine_visibility (tree decl) && !attr) { int depth = TMPL_ARGS_DEPTH (args); - if (DECL_VISIBILITY_SPECIFIED (decl)) + if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (TI_TEMPLATE (tinfo))) + /* Class template args don't affect template friends. */; + else if (DECL_VISIBILITY_SPECIFIED (decl)) { /* A class template member with explicit visibility overrides the class visibility, so we need to apply @@ -4026,6 +4028,7 @@ get_tls_init_fn (tree var) SET_DECL_LANGUAGE (fn, lang_c); TREE_PUBLIC (fn) = TREE_PUBLIC (var); DECL_ARTIFICIAL (fn) = true; + DECL_CONTEXT (fn) = FROB_CONTEXT (global_namespace); DECL_COMDAT (fn) = DECL_COMDAT (var); DECL_EXTERNAL (fn) = DECL_EXTERNAL (var); if (DECL_ONE_ONLY (var)) @@ -4085,7 +4088,7 @@ get_tls_wrapper_fn (tree var) TREE_PUBLIC (fn) = TREE_PUBLIC (var); DECL_ARTIFICIAL (fn) = true; DECL_IGNORED_P (fn) = 1; - DECL_CONTEXT (fn) = DECL_CONTEXT (var); + DECL_CONTEXT (fn) = FROB_CONTEXT (global_namespace); /* The wrapper is inline and emitted everywhere var is used. */ DECL_DECLARED_INLINE_P (fn) = true; if (TREE_PUBLIC (var)) @@ -4184,7 +4187,11 @@ start_objects (bool initp, unsigned priority, bool has_body, bool omp_target = false) { bool default_init = initp && priority == DEFAULT_INIT_PRIORITY; - bool is_module_init = default_init && module_global_init_needed (); + /* FIXME: We may eventually want to treat OpenMP offload initializers + in modules specially as well. */ + bool is_module_init = (default_init + && !omp_target + && module_global_init_needed ()); tree name = NULL_TREE; if (is_module_init) @@ -5876,12 +5883,8 @@ c_parse_final_cleanups (void) if (static_init_fini_fns[true]->get_or_insert (DEFAULT_INIT_PRIORITY)) has_module_inits = true; - if (flag_openmp) - { - if (!static_init_fini_fns[2 + true]) - static_init_fini_fns[2 + true] = priority_map_t::create_ggc (); - static_init_fini_fns[2 + true]->get_or_insert (DEFAULT_INIT_PRIORITY); - } + /* FIXME: We need to work out what static constructors on OpenMP offload + target in modules will look like. */ } /* Generate initialization and destruction functions for all @@ -6266,6 +6269,33 @@ mark_single_function (tree expr, tsubst_flags_t complain) return true; } +/* True iff we have started, but not finished, defining FUNCTION_DECL DECL. */ + +bool +fn_being_defined (tree decl) +{ + /* DECL_INITIAL is set to error_mark_node in grokfndecl for a definition, and + changed to BLOCK by poplevel at the end of the function. */ + return (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) == error_mark_node); +} + +/* True if DECL is an instantiation of a function template currently being + defined. */ + +bool +fn_template_being_defined (tree decl) +{ + if (TREE_CODE (decl) != FUNCTION_DECL + || !DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLOID_INSTANTIATION (decl) + || DECL_TEMPLATE_INSTANTIATED (decl)) + return false; + tree tinfo = DECL_TEMPLATE_INFO (decl); + tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)); + return fn_being_defined (pattern); +} + /* Mark DECL (either a _DECL or a BASELINK) as "used" in the program. If DECL is a specialization or implicitly declared class member, generate the actual definition. Return false if something goes @@ -6405,15 +6435,23 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) /* If DECL has a deduced return type, we need to instantiate it now to find out its type. For OpenMP user defined reductions, we need them - instantiated for reduction clauses which inline them by hand directly. */ + instantiated for reduction clauses which inline them by hand directly. + OpenMP declared mappers are used implicitly so must be instantiated + before they can be detected. */ if (undeduced_auto_decl (decl) || (VAR_P (decl) && VAR_HAD_UNKNOWN_BOUND (decl)) || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl))) + && DECL_OMP_DECLARE_REDUCTION_P (decl)) + || (TREE_CODE (decl) == VAR_DECL + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_DECLARE_MAPPER_P (decl))) maybe_instantiate_decl (decl); if (!decl_dependent_p (decl) + /* Don't require this yet for an instantiation of a function template + we're currently defining (c++/120555). */ + && !fn_template_being_defined (decl) && !require_deduced_type (decl, complain)) return false; @@ -6428,9 +6466,6 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) && uses_template_parms (DECL_TI_ARGS (decl))) return true; - if (!require_deduced_type (decl, complain)) - return false; - if (builtin_pack_fn_p (decl)) { error ("use of built-in parameter pack %qD outside of a template", diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index ec7527e..abeb028 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -38,7 +38,6 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "attribs.h" #include "pretty-print-format-impl.h" -#include "make-unique.h" #include "diagnostic-format-text.h" #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',') @@ -183,9 +182,10 @@ class cxx_format_postprocessor : public format_postprocessor : m_type_a (), m_type_b () {} - format_postprocessor *clone() const final override + std::unique_ptr<format_postprocessor> + clone() const final override { - return new cxx_format_postprocessor (); + return std::make_unique<cxx_format_postprocessor> (); } void handle (pretty_printer *pp) final override; @@ -194,6 +194,32 @@ class cxx_format_postprocessor : public format_postprocessor deferred_printed_type m_type_b; }; +/* Constructor and destructor for cxx_dump_pretty_printer, defined here to + avoid needing to move cxx_format_postprocessor into the header as well. */ + +cxx_dump_pretty_printer:: +cxx_dump_pretty_printer (int phase) + : phase (phase) +{ + outf = dump_begin (phase, &flags); + if (outf) + { + pp_format_decoder (this) = cp_printer; + set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ()); + set_output_stream (outf); + } +} + +cxx_dump_pretty_printer:: +~cxx_dump_pretty_printer () +{ + if (outf) + { + pp_flush (this); + dump_end (phase, outf); + } +} + /* Return the in-scope template that's currently being parsed, or NULL_TREE otherwise. */ @@ -275,14 +301,14 @@ void cxx_initialize_diagnostics (diagnostic_context *context) { cxx_pretty_printer *pp = new cxx_pretty_printer (); - pp_format_postprocessor (pp) = new cxx_format_postprocessor (); + pp->set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ()); context->set_pretty_printer (std::unique_ptr<pretty_printer> (pp)); c_common_diagnostics_set_defaults (context); diagnostic_text_starter (context) = cp_diagnostic_text_starter; /* diagnostic_finalizer is already c_diagnostic_text_finalizer. */ context->set_format_decoder (cp_printer); - context->m_adjust_diagnostic_info = cp_adjust_diagnostic_info; + context->set_adjust_diagnostic_info_callback (cp_adjust_diagnostic_info); } /* Dump an '@module' name suffix for DECL, if it's attached to an import. */ @@ -542,12 +568,13 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, /* If the template argument repeats the template parameter (T = T), skip the parameter.*/ if (arg && TREE_CODE (arg) == TEMPLATE_TYPE_PARM - && TREE_CODE (parm_i) == TREE_LIST - && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL - && TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i))) - == TEMPLATE_TYPE_PARM - && DECL_NAME (TREE_VALUE (parm_i)) - == DECL_NAME (TREE_CHAIN (arg))) + && arg == TYPE_MAIN_VARIANT (arg) + && TREE_CODE (parm_i) == TREE_LIST + && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL + && (TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i))) + == TEMPLATE_TYPE_PARM) + && (DECL_NAME (TREE_VALUE (parm_i)) + == DECL_NAME (TYPE_STUB_DECL (arg)))) continue; semicolon_or_introducer (); @@ -1255,12 +1282,37 @@ dump_global_iord (cxx_pretty_printer *pp, tree t) pp_printf (pp, p, DECL_SOURCE_FILE (t)); } +/* Write a representation of OpenMP "declare mapper" T to PP in a manner + suitable for error messages. */ + +static void +dump_omp_declare_mapper (cxx_pretty_printer *pp, tree t, int flags) +{ + pp_string (pp, "#pragma omp declare mapper"); + if (t == NULL_TREE || t == error_mark_node) + return; + pp_space (pp); + pp_cxx_left_paren (pp); + if (OMP_DECLARE_MAPPER_ID (t)) + { + pp_cxx_tree_identifier (pp, OMP_DECLARE_MAPPER_ID (t)); + pp_colon (pp); + } + dump_type (pp, TREE_TYPE (t), flags); + pp_cxx_right_paren (pp); +} + static void dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) { if (VAR_P (t) && DECL_NTTP_OBJECT_P (t)) return dump_expr (pp, DECL_INITIAL (t), flags); + if (TREE_CODE (t) == VAR_DECL + && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t)) + return dump_omp_declare_mapper (pp, DECL_INITIAL (t), flags); + if (flags & TFF_DECL_SPECIFIERS) { if (concept_definition_p (t)) @@ -3217,6 +3269,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) break; } + case CO_AWAIT_EXPR: + pp_cxx_ws_string (pp, "co_await"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_YIELD_EXPR: + pp_cxx_ws_string (pp, "co_yield"); + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + break; + + case CO_RETURN_EXPR: + pp_cxx_ws_string (pp, "co_return"); + if (TREE_OPERAND (t, 0)) + { + pp_cxx_whitespace (pp); + dump_expr (pp, TREE_OPERAND (t, 0), flags); + } + break; + /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call `report_error_function'. That could cause an infinite loop. */ @@ -3788,18 +3861,18 @@ cp_print_error_function (diagnostic_text_output_format &text_output, { if (text_output.show_column_p () && s.column != 0) pp_printf (pp, - _(" inlined from %qD at %r%s:%d:%d%R"), + G_(" inlined from %qD at %r%s:%d:%d%R"), fndecl, "locus", s.file, s.line, s.column); else pp_printf (pp, - _(" inlined from %qD at %r%s:%d%R"), + G_(" inlined from %qD at %r%s:%d%R"), fndecl, "locus", s.file, s.line); } else - pp_printf (pp, _(" inlined from %qD"), + pp_printf (pp, G_(" inlined from %qD"), fndecl); } } @@ -3825,22 +3898,22 @@ function_category (tree fn) && DECL_FUNCTION_MEMBER_P (fn)) { if (DECL_STATIC_FUNCTION_P (fn)) - return _("In static member function %qD"); + return G_("In static member function %qD"); else if (DECL_COPY_CONSTRUCTOR_P (fn)) - return _("In copy constructor %qD"); + return G_("In copy constructor %qD"); else if (DECL_CONSTRUCTOR_P (fn)) - return _("In constructor %qD"); + return G_("In constructor %qD"); else if (DECL_DESTRUCTOR_P (fn)) - return _("In destructor %qD"); + return G_("In destructor %qD"); else if (LAMBDA_FUNCTION_P (fn)) - return _("In lambda function"); + return G_("In lambda function"); else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) - return _("In explicit object member function %qD"); + return G_("In explicit object member function %qD"); else - return _("In member function %qD"); + return G_("In member function %qD"); } else - return _("In function %qD"); + return G_("In function %qD"); } /* Disable warnings about missing quoting in GCC diagnostics for @@ -3867,8 +3940,8 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output) char *indent = text_output.build_indent_prefix (true); pp_verbatim (text_output.get_printer (), p->list_p () - ? _("%s%s%sIn substitution of %qS:\n") - : _("%s%s%sIn instantiation of %q#D:\n"), + ? G_("%s%s%sIn substitution of %qS:\n") + : G_("%s%s%sIn instantiation of %q#D:\n"), indent, show_file ? LOCATION_FILE (location) : "", show_file ? ": " : "", @@ -3888,10 +3961,10 @@ print_location (diagnostic_text_output_format &text_output, expanded_location xloc = expand_location (loc); pretty_printer *const pp = text_output.get_printer (); if (text_output.show_column_p ()) - pp_verbatim (pp, _("%r%s:%d:%d:%R "), + pp_verbatim (pp, G_("%r%s:%d:%d:%R "), "locus", xloc.file, xloc.line, xloc.column); else - pp_verbatim (pp, _("%r%s:%d:%R "), + pp_verbatim (pp, G_("%r%s:%d:%R "), "locus", xloc.file, xloc.line); } @@ -3984,22 +4057,22 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou if (t->list_p ()) pp_verbatim (pp, recursive_p - ? _("recursively required by substitution of %qS\n") - : _("required by substitution of %qS\n"), + ? G_("recursively required by substitution of %qS\n") + : G_("required by substitution of %qS\n"), t->get_node ()); else pp_verbatim (pp, recursive_p - ? _("recursively required from %q#D\n") - : _("required from %q#D\n"), + ? G_("recursively required from %q#D\n") + : G_("required from %q#D\n"), t->get_node ()); } else { pp_verbatim (pp, recursive_p - ? _("recursively required from here\n") - : _("required from here\n")); + ? G_("recursively required from here\n") + : G_("required from here\n")); } } @@ -4049,8 +4122,8 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, loc); pp_verbatim (text_output.get_printer (), - _("[ skipping %d instantiation contexts," - " use -ftemplate-backtrace-limit=0 to disable ]\n"), + G_("[ skipping %d instantiation contexts," + " use -ftemplate-backtrace-limit=0 to disable ]\n"), skip); do { loc = t->locus; @@ -4101,7 +4174,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output) pretty_printer *const pp = text_output.get_printer (); auto_context_line sentinel (text_output, EXPR_LOCATION (t)); pp_verbatim (pp, - _("in %<constexpr%> expansion of %qs"), + G_("in %<constexpr%> expansion of %qs"), s); pp_newline (pp); } @@ -4114,7 +4187,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl)); pretty_printer *const pp = text_output.get_printer (); - pp_verbatim (pp, "required by the constraints of %q#D\n", decl); + pp_verbatim (pp, G_("required by the constraints of %q#D\n"), decl); } static void @@ -4129,7 +4202,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output, cxx_pretty_printer *const pp = (cxx_pretty_printer *)text_output.get_printer (); - pp_verbatim (pp, "required for the satisfaction of %qE", expr); + pp_verbatim (pp, G_("required for the satisfaction of %qE"), expr); if (map && map != error_mark_node) { tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); @@ -4151,7 +4224,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, input_location); pretty_printer *const pp = text_output.get_printer (); - pp_verbatim (pp, "required for constraint satisfaction\n"); + pp_verbatim (pp, G_("required for constraint satisfaction\n")); return NULL_TREE; } if (DECL_P (src)) @@ -4180,11 +4253,10 @@ print_requires_expression_info (diagnostic_text_output_format &text_output, auto_context_line sentinel (text_output, cp_expr_loc_or_input_loc (expr)); cxx_pretty_printer *const pp = static_cast <cxx_pretty_printer *> (text_output.get_printer ()); - pp_verbatim (pp, "in requirements "); tree parms = TREE_OPERAND (expr, 0); - if (parms) - pp_verbatim (pp, "with "); + pp_verbatim (pp, parms ? G_("in requirements with ") + : G_("in requirements ")); while (parms) { pp_verbatim (pp, "%q#D", parms); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index e589e45..0a389fb 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3010,7 +3010,6 @@ build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree itype2) tree atype1 = build_cplus_array_type (sizetype, itype1); tree atype2 = build_cplus_array_type (elt_type, itype2); tree rtype = cxx_make_type (RECORD_TYPE); - TYPE_NAME (rtype) = heap_identifier; tree fld1 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype1); tree fld2 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype2); DECL_FIELD_CONTEXT (fld1) = rtype; @@ -3019,7 +3018,16 @@ build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree itype2) DECL_ARTIFICIAL (fld2) = true; TYPE_FIELDS (rtype) = fld1; DECL_CHAIN (fld1) = fld2; + TYPE_ARTIFICIAL (rtype) = true; layout_type (rtype); + + tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, heap_identifier, rtype); + TYPE_NAME (rtype) = decl; + TYPE_STUB_DECL (rtype) = decl; + DECL_CONTEXT (decl) = NULL_TREE; + DECL_ARTIFICIAL (decl) = true; + layout_decl (decl, 0); + return rtype; } @@ -3405,7 +3413,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, errval = throw_bad_array_new_length (); if (outer_nelts_check != NULL_TREE) size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval); - size = cp_fully_fold (size); + size = fold_to_constant (size); /* Create the argument list. */ vec_safe_insert (*placement, 0, size); /* Do name-lookup to find the appropriate operator. */ @@ -3462,7 +3470,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, outer_nelts_check = NULL_TREE; } - size = cp_fully_fold (size); + size = fold_to_constant (size); /* If size is zero e.g. due to type having zero size, try to preserve outer_nelts for constant expression evaluation purposes. */ @@ -4747,7 +4755,8 @@ build_vec_init (tree base, tree maxindex, tree init, itself. But that breaks when gimplify_target_expr adds a clobber cleanup that runs before the build_vec_init cleanup. */ if (cleanup_flags) - vec_safe_push (*cleanup_flags, build_tree_list (iterator, maxindex)); + vec_safe_push (*cleanup_flags, + build_tree_list (rval, build_zero_cst (ptype))); } /* Should we try to create a constant initializer? */ diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index f0a54b6..2a9061a 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -218,9 +218,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, tree type; bool is_this = is_this_parameter (tree_strip_nop_conversions (expr)); - if (is_this) - type = TREE_TYPE (expr); - else if (explicit_init_p) + if (explicit_init_p) { tree auto_node = make_auto (); @@ -259,7 +257,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, type = non_reference (unlowered_expr_type (expr)); - if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE) + if ((by_reference_p && !is_this) || TREE_CODE (type) == FUNCTION_TYPE) type = build_reference_type (type); } @@ -348,7 +346,11 @@ insert_capture_proxy (tree var) /* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */ var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var); - tree stmt_list = (*stmt_list_stack)[1]; + /* The first stmt_list is from start_preparsed_function. Then there's a + possible stmt_list from begin_eh_spec_block, then the one from the + lambda's outer {}. */ + unsigned index = 1 + use_eh_spec_block (current_function_decl); + tree stmt_list = (*stmt_list_stack)[index]; gcc_assert (stmt_list); append_to_statement_list_force (var, &stmt_list); } @@ -436,13 +438,21 @@ build_capture_proxy (tree member, tree init) else name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); - type = lambda_proxy_type (object); - - if (name == this_identifier && !INDIRECT_TYPE_P (type)) + if (name == this_identifier && TYPE_PTR_P (TREE_TYPE (member))) + /* Avoid DECLTYPE_TYPE for by-ref 'this' capture in an xobj lambda; the + constness of the closure doesn't matter just like it doesn't matter to + other by-ref capture. It's simpler to handle this special case here + than in lambda_proxy_type. */ + type = TREE_TYPE (member); + else { - type = build_pointer_type (type); - type = cp_build_qualified_type (type, TYPE_QUAL_CONST); - object = build_fold_addr_expr_with_type (object, type); + type = lambda_proxy_type (object); + if (name == this_identifier) + { + type = build_pointer_type (type); + type = cp_build_qualified_type (type, TYPE_QUAL_CONST); + object = build_fold_addr_expr_with_type (object, type); + } } if (DECL_VLA_CAPTURE_P (member)) @@ -917,8 +927,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p) else { /* To make sure that current_class_ref is for the lambda. */ - gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) - == LAMBDA_EXPR_CLOSURE (lambda)); + gcc_assert (!current_class_ref + || (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) + == LAMBDA_EXPR_CLOSURE (lambda))); result = this_capture; @@ -1033,12 +1044,9 @@ current_nonlambda_function (void) tree nonlambda_method_basetype (void) { - if (!current_class_ref) - return NULL_TREE; - tree type = current_class_type; if (!type || !LAMBDA_TYPE_P (type)) - return type; + return current_class_ref ? type : NULL_TREE; while (true) { @@ -1050,7 +1058,7 @@ nonlambda_method_basetype (void) tree fn = TYPE_CONTEXT (type); if (!fn || TREE_CODE (fn) != FUNCTION_DECL - || !DECL_IOBJ_MEMBER_FUNCTION_P (fn)) + || !DECL_OBJECT_MEMBER_FUNCTION_P (fn)) /* No enclosing non-lambda method. */ return NULL_TREE; if (!LAMBDA_FUNCTION_P (fn)) @@ -1858,6 +1866,12 @@ prune_lambda_captures (tree body) cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars); + tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam))); + bool noexcept_p = (bind_expr + && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR); + if (noexcept_p) + bind_expr = expr_single (TREE_OPERAND (bind_expr, 0)); + tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam)); for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; ) { @@ -1865,11 +1879,23 @@ prune_lambda_captures (tree body) if (tree var = var_to_maybe_prune (cap)) { tree **use = const_vars.get (var); - if (use && TREE_CODE (**use) == DECL_EXPR) + if (TREE_CODE (**use) == DECL_EXPR) { /* All uses of this capture were folded away, leaving only the proxy declaration. */ + if (noexcept_p) + { + /* We didn't handle noexcept lambda captures correctly before + the fix for PR c++/119764. */ + if (abi_version_crosses (21)) + warning_at (location_of (lam), OPT_Wabi, "%qD is no longer" + " captured in noexcept lambda in ABI v21 " + "(GCC 16)", var); + if (!abi_version_at_least (21)) + goto next; + } + /* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST. */ *capp = TREE_CHAIN (cap); @@ -1879,12 +1905,27 @@ prune_lambda_captures (tree body) fieldp = &DECL_CHAIN (*fieldp); *fieldp = DECL_CHAIN (*fieldp); + /* And out of the bindings for the function. */ + tree *blockp = &BLOCK_VARS (current_binding_level->blocks); + while (*blockp != DECL_EXPR_DECL (**use)) + blockp = &DECL_CHAIN (*blockp); + *blockp = DECL_CHAIN (*blockp); + + /* And maybe out of the vars declared in the containing + BIND_EXPR, if it's listed there. */ + tree *bindp = &BIND_EXPR_VARS (bind_expr); + while (*bindp && *bindp != DECL_EXPR_DECL (**use)) + bindp = &DECL_CHAIN (*bindp); + if (*bindp) + *bindp = DECL_CHAIN (*bindp); + /* And remove the capture proxy declaration. */ **use = void_node; continue; } } + next: capp = &TREE_CHAIN (cap); } } diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index c12b084..08a6348 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -749,6 +749,9 @@ unqualified_name_lookup_error (tree name, location_t loc) if (IDENTIFIER_ANY_OP_P (name)) error_at (loc, "%qD not defined", name); + else if (!flag_concepts && name == ridpointers[(int)RID_REQUIRES]) + error_at (loc, "%<requires%> only available with %<-std=c++20%> or " + "%<-fconcepts%>"); else { if (!objc_diagnose_private_ivar (name)) @@ -1079,15 +1082,17 @@ copy_lang_type (tree node) if (! TYPE_LANG_SPECIFIC (node)) return; - auto *lt = (struct lang_type *) ggc_internal_alloc (sizeof (struct lang_type)); + size_t sz = (c_dialect_objc () ? sizeof (struct lang_type) + : offsetof (struct lang_type, info)); + auto *lt = (struct lang_type *) ggc_internal_alloc (sz); - memcpy (lt, TYPE_LANG_SPECIFIC (node), (sizeof (struct lang_type))); + memcpy (lt, TYPE_LANG_SPECIFIC (node), sz); TYPE_LANG_SPECIFIC (node) = lt; if (GATHER_STATISTICS) { tree_node_counts[(int)lang_type] += 1; - tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + tree_node_sizes[(int)lang_type] += sz; } } @@ -1111,14 +1116,15 @@ maybe_add_lang_type_raw (tree t) if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t))) return false; - auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc - (sizeof (struct lang_type))); + size_t sz = (c_dialect_objc () ? sizeof (struct lang_type) + : offsetof (struct lang_type, info)); + auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc (sz)); TYPE_LANG_SPECIFIC (t) = lt; if (GATHER_STATISTICS) { tree_node_counts[(int)lang_type] += 1; - tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + tree_node_sizes[(int)lang_type] += sz; } return true; @@ -1132,8 +1138,8 @@ cxx_make_type (enum tree_code code MEM_STAT_DECL) if (maybe_add_lang_type_raw (t)) { /* Set up some flags that give proper default behavior. */ - struct c_fileinfo *finfo = - get_fileinfo (LOCATION_FILE (input_location)); + struct c_fileinfo *finfo + = get_fileinfo (LOCATION_FILE (input_location)); SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown); CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only; } diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 02129c6..13d5ded 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1048,6 +1048,12 @@ decl_mangling_context (tree decl) tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)); if (extra) return extra; + tcontext = CP_DECL_CONTEXT (decl); + if (LAMBDA_TYPE_P (tcontext)) + /* Lambda type context means this lambda appears between the + lambda-introducer and the open brace of another lambda (c++/119175). + That isn't a real scope; look further into the enclosing scope. */ + return decl_mangling_context (TYPE_NAME (tcontext)); } else if (template_type_parameter_p (decl)) /* template type parms have no mangling context. */ @@ -4446,23 +4452,12 @@ static tree mangle_decl_string (const tree decl) { tree result; - tree saved_fn = NULL_TREE; - bool template_p = false; + tree saved_fn = current_function_decl; /* We shouldn't be trying to mangle an uninstantiated template. */ gcc_assert (!type_dependent_expression_p (decl)); - if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl)) - { - struct tinst_level *tl = current_instantiation (); - if ((!tl || tl->maybe_get_node () != decl) - && push_tinst_level (decl)) - { - template_p = true; - saved_fn = current_function_decl; - current_function_decl = NULL_TREE; - } - } + current_function_decl = NULL_TREE; iloc_sentinel ils (DECL_SOURCE_LOCATION (decl)); start_mangling (decl); @@ -4477,12 +4472,7 @@ mangle_decl_string (const tree decl) fprintf (stderr, "mangle_decl_string = '%s'\n\n", IDENTIFIER_POINTER (result)); - if (template_p) - { - pop_tinst_level (); - current_function_decl = saved_fn; - } - + current_function_decl = saved_fn; return result; } diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 05c19cf..a4089c5 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from) const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { + if (ABSTRACT_CLASS_TYPE_P (to)) + return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; if (!TYPE_REF_P (to)) @@ -2330,6 +2332,37 @@ constructible_expr (tree to, tree from) return expr; } +/* Valid if "Either T is a reference type, or T is a complete object type for + which the expression declval<U&>().~U() is well-formed when treated as an + unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>." + + For a class U, return the destructor call; otherwise return void_node if + valid or error_mark_node if not. */ + +static tree +destructible_expr (tree to) +{ + cp_unevaluated cp_uneval_guard; + int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; + if (TYPE_REF_P (to)) + return void_node; + if (!COMPLETE_TYPE_P (complete_type (to))) + return error_mark_node; + to = strip_array_types (to); + if (CLASS_TYPE_P (to)) + { + to = build_trait_object (to); + return build_delete (input_location, TREE_TYPE (to), to, + sfk_complete_destructor, flags, 0, tf_none); + } + /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T + shall be a scalar type.... */ + else if (scalarish_type_p (to)) + return void_node; + else + return error_mark_node; +} + /* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for assignment or a list of types for construction. */ @@ -2339,13 +2372,15 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) { to = complete_type (to); deferring_access_check_sentinel acs (dk_no_deferred); - if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to) + if (VOID_TYPE_P (to) || (from && FUNC_OR_METHOD_TYPE_P (from) && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))) return error_mark_node; tree expr; if (code == MODIFY_EXPR) expr = assignable_expr (to, from); + else if (code == BIT_NOT_EXPR) + expr = destructible_expr (to); else if (trivial && TREE_VEC_LENGTH (from) > 1 && cxx_dialect < cxx20) return error_mark_node; // only 0- and 1-argument ctors can be trivial @@ -2949,7 +2984,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, && BINFO_VIRTUAL_P (base_binfo) && fn && TREE_CODE (fn) == FUNCTION_DECL && move_fn_p (fn) && !trivial_fn_p (fn) - && vbase_has_user_provided_move_assign (BINFO_TYPE (base_binfo))) + && vbase_has_user_provided_move_assign (BINFO_TYPE (base_binfo)) + && warning_enabled_at (DECL_SOURCE_LOCATION (fn), + OPT_Wvirtual_move_assign)) warning (OPT_Wvirtual_move_assign, "defaulted move assignment for %qT calls a non-trivial " "move assignment operator for virtual base %qT", @@ -2987,7 +3024,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, /* Vbase cdtors are not relevant. */; else { - if (constexpr_p) + if (constexpr_p && cxx_dialect < cxx26) *constexpr_p = false; FOR_EACH_VEC_ELT (*vbases, i, base_binfo) @@ -3914,5 +3951,26 @@ num_artificial_parms_for (const_tree fn) return count; } +/* Return value of the __builtin_type_order trait. */ + +tree +type_order_value (tree type1, tree type2) +{ + tree rettype = lookup_comparison_category (cc_strong_ordering); + if (rettype == error_mark_node) + return rettype; + int ret; + if (type1 == type2) + ret = 0; + else + { + const char *name1 = ASTRDUP (mangle_type_string (type1)); + const char *name2 = mangle_type_string (type2); + ret = strcmp (name1, name2); + } + return lookup_comparison_result (cc_strong_ordering, rettype, + ret == 0 ? 0 : ret > 0 ? 1 : 2); +} + #include "gt-cp-method.h" diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 37fab5b..c8e79f3 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2811,12 +2811,13 @@ enum tree_tag { tt_decl, /* By-value mergeable decl. */ tt_tpl_parm, /* Template parm. */ - /* The ordering of the following 4 is relied upon in + /* The ordering of the following 5 is relied upon in trees_out::tree_node. */ tt_id, /* Identifier node. */ tt_conv_id, /* Conversion operator name. */ tt_anon_id, /* Anonymous name. */ tt_lambda_id, /* Lambda name. */ + tt_internal_id, /* Internal name. */ tt_typedef_type, /* A (possibly implicit) typedefed type. */ tt_derived_type, /* A type derived from another type. */ @@ -3096,6 +3097,9 @@ private: unsigned section; bool writing_local_entities; /* Whether we might walk into a TU-local entity we need to emit placeholders for. */ + bool walking_bit_field_unit; /* Whether we're walking the underlying + storage for a bit field. There's no other + great way to detect this. */ #if CHECKING_P int importedness; /* Checker that imports not occurring inappropriately. +ve imports ok, @@ -3262,7 +3266,7 @@ trees_out::trees_out (allocator *mem, module_state *state, depset::hash &deps, unsigned section) :parent (mem), state (state), tree_map (500), dep_hash (&deps), ref_num (0), section (section), - writing_local_entities (false) + writing_local_entities (false), walking_bit_field_unit (false) { #if CHECKING_P importedness = 0; @@ -3879,6 +3883,10 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr); bool read_macro_maps (line_map_uint_t); + void write_diagnostic_classification (elf_out *, diagnostic_context *, + unsigned *); + bool read_diagnostic_classification (diagnostic_context *); + private: void write_define (bytes_out &, const cpp_macro *); cpp_macro *read_define (bytes_in &, cpp_reader *) const; @@ -5546,8 +5554,10 @@ trees_in::start (unsigned code) enum class importer_interface { unknown, /* The definition may or may not need to be emitted. */ - always_import, /* The definition can always be found in another TU. */ - always_emit, /* The definition must be emitted in the importer's TU. */ + external, /* The definition can always be found in another TU. */ + internal, /* The definition should be emitted in the importer's TU. */ + always_emit, /* The definition must be emitted in the importer's TU, + regardless of if it's used or not. */ }; /* Returns what kind of interface an importer will have of DECL. */ @@ -5558,13 +5568,13 @@ get_importer_interface (tree decl) /* Internal linkage entities must be emitted in each importer if there is a definition available. */ if (!TREE_PUBLIC (decl)) - return importer_interface::always_emit; + return importer_interface::internal; - /* Entities that aren't vague linkage are either not definitions or - will be emitted in this TU, so importers can just refer to an - external definition. */ + /* Other entities that aren't vague linkage are either not definitions + or will be publicly emitted in this TU, so importers can just refer + to an external definition. */ if (!vague_linkage_p (decl)) - return importer_interface::always_import; + return importer_interface::external; /* For explicit instantiations, importers can always rely on there being a definition in another TU, unless this is a definition @@ -5574,13 +5584,13 @@ get_importer_interface (tree decl) && DECL_EXPLICIT_INSTANTIATION (decl)) return (header_module_p () && !DECL_EXTERNAL (decl) ? importer_interface::always_emit - : importer_interface::always_import); + : importer_interface::external); /* A gnu_inline function is never emitted in any TU. */ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl))) - return importer_interface::always_import; + return importer_interface::external; /* Everything else has vague linkage. */ return importer_interface::unknown; @@ -5723,28 +5733,16 @@ trees_out::core_bools (tree t, bits_out& bits) == that was a lie, it is here */ bool is_external = t->decl_common.decl_flag_1; - if (!is_external) - /* decl_flag_1 is DECL_EXTERNAL. Things we emit here, might - well be external from the POV of an importer. */ - // FIXME: Do we need to know if this is a TEMPLATE_RESULT -- - // a flag from the caller? - switch (code) - { - default: - break; - - case VAR_DECL: - if (TREE_PUBLIC (t) - && DECL_VTABLE_OR_VTT_P (t)) - /* We handle vtable linkage specially. */ - is_external = true; - gcc_fallthrough (); - case FUNCTION_DECL: - if (get_importer_interface (t) - == importer_interface::always_import) - is_external = true; - break; - } + /* maybe_emit_vtables relies on vtables being marked as + DECL_EXTERNAL and DECL_NOT_REALLY_EXTERN before processing. */ + if (!is_external && VAR_P (t) && DECL_VTABLE_OR_VTT_P (t)) + is_external = true; + /* Things we emit here might well be external from the POV of an + importer. */ + if (!is_external + && VAR_OR_FUNCTION_DECL_P (t) + && get_importer_interface (t) == importer_interface::external) + is_external = true; WB (is_external); } @@ -6024,7 +6022,7 @@ trees_out::lang_decl_bools (tree t, bits_out& bits) WB (lang->u.fn.has_dependent_explicit_spec_p); WB (lang->u.fn.immediate_fn_p); WB (lang->u.fn.maybe_deleted); - /* We do not stream lang->u.fn.implicit_constexpr. */ + WB (lang->u.fn.implicit_constexpr); WB (lang->u.fn.escalated_p); WB (lang->u.fn.xobj_func); goto lds_min; @@ -6095,7 +6093,7 @@ trees_in::lang_decl_bools (tree t, bits_in& bits) RB (lang->u.fn.has_dependent_explicit_spec_p); RB (lang->u.fn.immediate_fn_p); RB (lang->u.fn.maybe_deleted); - /* We do not stream lang->u.fn.implicit_constexpr. */ + RB (lang->u.fn.implicit_constexpr); RB (lang->u.fn.escalated_p); RB (lang->u.fn.xobj_func); goto lds_min; @@ -6517,7 +6515,10 @@ trees_out::core_vals (tree t) case FIELD_DECL: WT (t->field_decl.offset); WT (t->field_decl.bit_field_type); - WT (t->field_decl.qualifier); /* bitfield unit. */ + { + auto ovr = make_temp_override (walking_bit_field_unit, true); + WT (t->field_decl.qualifier); /* bitfield unit. */ + } WT (t->field_decl.bit_offset); WT (t->field_decl.fcontext); WT (t->decl_common.initial); @@ -7386,7 +7387,7 @@ trees_out::lang_decl_vals (tree t) WU (lang->u.fn.ovl_op_code); } - if (DECL_CLASS_SCOPE_P (t)) + if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t)) WT (lang->u.fn.context); if (lang->u.fn.thunk_p) @@ -7470,7 +7471,7 @@ trees_in::lang_decl_vals (tree t) lang->u.fn.ovl_op_code = code; } - if (DECL_CLASS_SCOPE_P (t)) + if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t)) RT (lang->u.fn.context); if (lang->u.fn.thunk_p) @@ -8097,18 +8098,37 @@ trees_in::install_entity (tree decl) gcc_checking_assert (!existed); slot = ident; } - else if (state->is_partition ()) + else { - /* The decl is already in the entity map, but we see it again now from a - partition: we want to overwrite if the original decl wasn't also from - a (possibly different) partition. Otherwise, for things like template - instantiations, make_dependency might not realise that this is also - provided from a partition and should be considered part of this module - (and thus always emitted into the primary interface's CMI). */ unsigned *slot = entity_map->get (DECL_UID (decl)); - module_state *imp = import_entity_module (*slot); - if (!imp->is_partition ()) - *slot = ident; + + /* The entity must be in the entity map already. However, DECL may + be the DECL_TEMPLATE_RESULT of an existing partial specialisation + if we matched it while streaming another instantiation; in this + case we already registered that TEMPLATE_DECL. */ + if (!slot) + { + tree type = TREE_TYPE (decl); + gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL + && CLASS_TYPE_P (type) + && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)); + slot = entity_map->get (DECL_UID (CLASSTYPE_TI_TEMPLATE (type))); + } + gcc_checking_assert (slot); + + if (state->is_partition ()) + { + /* The decl is already in the entity map, but we see it again now + from a partition: we want to overwrite if the original decl + wasn't also from a (possibly different) partition. Otherwise, + for things like template instantiations, make_dependency might + not realise that this is also provided from a partition and + should be considered part of this module (and thus always + emitted into the primary interface's CMI). */ + module_state *imp = import_entity_module (*slot); + if (!imp->is_partition ()) + *slot = ident; + } } return true; @@ -8199,6 +8219,10 @@ trees_out::decl_value (tree decl, depset *dep) inner = DECL_TEMPLATE_RESULT (decl); inner_tag = insert (inner, WK_value); + /* On stream-in we assume that a template and its result will + have the same type. */ + gcc_checking_assert (TREE_TYPE (decl) == TREE_TYPE (inner)); + if (streaming_p ()) { int code = TREE_CODE (inner); @@ -9353,6 +9377,7 @@ trees_out::type_node (tree type) tree root = (TYPE_NAME (type) ? TREE_TYPE (TYPE_NAME (type)) : TYPE_MAIN_VARIANT (type)); + gcc_checking_assert (root); if (type != root) { @@ -9431,6 +9456,8 @@ trees_out::type_node (tree type) || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == ENUMERAL_TYPE) { + gcc_checking_assert (DECL_P (name)); + /* We can meet template parms that we didn't meet in the tpl_parms walk, because we're referring to a derived type that was previously constructed from equivalent template @@ -9645,11 +9672,14 @@ trees_out::tree_value (tree t) if (DECL_P (t)) /* No template, type, var or function, except anonymous - non-context vars. */ + non-context vars and types. */ gcc_checking_assert ((TREE_CODE (t) != TEMPLATE_DECL - && TREE_CODE (t) != TYPE_DECL + && (TREE_CODE (t) != TYPE_DECL + || (DECL_ARTIFICIAL (t) && !DECL_CONTEXT (t))) && (TREE_CODE (t) != VAR_DECL - || (!DECL_NAME (t) && !DECL_CONTEXT (t))) + || ((!DECL_NAME (t) + || IDENTIFIER_INTERNAL_P (DECL_NAME (t))) + && !DECL_CONTEXT (t))) && TREE_CODE (t) != FUNCTION_DECL)); if (streaming_p ()) @@ -9661,7 +9691,7 @@ trees_out::tree_value (tree t) tree_node_bools (t); } - if (TREE_CODE (t) == TREE_BINFO) + if (TREE_CODE (t) == TREE_BINFO) /* Binfos are decl-like and need merging information. */ binfo_mergeable (t); @@ -9670,8 +9700,57 @@ trees_out::tree_value (tree t) dump (dumper::TREE) && dump ("Writing tree:%d %C:%N", tag, TREE_CODE (t), t); + int type_tag = 0; + tree type = NULL_TREE; + if (TREE_CODE (t) == TYPE_DECL) + { + type = TREE_TYPE (t); + + /* We only support a limited set of features for uncontexted types; + these are typically types created in the language-independent + parts of the frontend (such as ubsan). */ + gcc_checking_assert (RECORD_OR_UNION_TYPE_P (type) + && TYPE_MAIN_VARIANT (type) == type + && TYPE_NAME (type) == t + && TYPE_STUB_DECL (type) == t + && !TYPE_VFIELD (type) + && !TYPE_BINFO (type) + && !CLASS_TYPE_P (type)); + + if (streaming_p ()) + { + start (type); + tree_node_bools (type); + } + + type_tag = insert (type, WK_value); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Writing type: %d %C:%N", type_tag, + TREE_CODE (type), type); + } + tree_node_vals (t); + if (type) + { + tree_node_vals (type); + tree_node (TYPE_SIZE (type)); + tree_node (TYPE_SIZE_UNIT (type)); + chained_decls (TYPE_FIELDS (type)); + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Written type:%d %C:%N", type_tag, TREE_CODE (type), type); + } + + /* For uncontexted VAR_DECLs we need to stream the definition so that + importers can recreate their value. */ + if (TREE_CODE (t) == VAR_DECL) + { + gcc_checking_assert (!DECL_NONTRIVIALLY_INITIALIZED_P (t)); + tree_node (DECL_INITIAL (t)); + } + if (streaming_p ()) dump (dumper::TREE) && dump ("Written tree:%d %C:%N", tag, TREE_CODE (t), t); } @@ -9710,14 +9789,55 @@ trees_in::tree_value () dump (dumper::TREE) && dump ("Reading tree:%d %C", tag, TREE_CODE (t)); - if (!tree_node_vals (t)) + int type_tag = 0; + tree type = NULL_TREE; + if (TREE_CODE (t) == TYPE_DECL) + { + type = start (); + if (!type || !tree_node_bools (type)) + t = NULL_TREE; + + type_tag = insert (type); + if (t) + dump (dumper::TREE) + && dump ("Reading type:%d %C", type_tag, TREE_CODE (type)); + } + + if (!t) { +bail: back_refs[~tag] = NULL_TREE; + if (type_tag) + back_refs[~type_tag] = NULL_TREE; set_overrun (); - /* Bail. */ return NULL_TREE; } + if (!tree_node_vals (t)) + goto bail; + + if (type) + { + if (!tree_node_vals (type)) + goto bail; + + TYPE_SIZE (type) = tree_node (); + TYPE_SIZE_UNIT (type) = tree_node (); + TYPE_FIELDS (type) = chained_decls (); + if (get_overrun ()) + goto bail; + + dump (dumper::TREE) + && dump ("Read type:%d %C:%N", type_tag, TREE_CODE (type), type); + } + + if (TREE_CODE (t) == VAR_DECL) + { + DECL_INITIAL (t) = tree_node (); + if (TREE_STATIC (t)) + varpool_node::finalize_decl (t); + } + if (TREE_CODE (t) == LAMBDA_EXPR && CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t))) { @@ -9860,10 +9980,13 @@ trees_out::tree_node (tree t) if (TREE_CODE (t) == IDENTIFIER_NODE) { - /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id. */ + /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id, + tt_internal_id. */ int code = tt_id; if (IDENTIFIER_ANON_P (t)) code = IDENTIFIER_LAMBDA_P (t) ? tt_lambda_id : tt_anon_id; + else if (IDENTIFIER_INTERNAL_P (t)) + code = tt_internal_id; else if (IDENTIFIER_CONV_OP_P (t)) code = tt_conv_id; @@ -9878,13 +10001,15 @@ trees_out::tree_node (tree t) } else if (code == tt_id && streaming_p ()) str (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t)); + else if (code == tt_internal_id && streaming_p ()) + str (prefix_for_internal_label (t)); int tag = insert (t); if (streaming_p ()) { - /* We know the ordering of the 4 id tags. */ + /* We know the ordering of the 5 id tags. */ static const char *const kinds[] = - {"", "conv_op ", "anon ", "lambda "}; + {"", "conv_op ", "anon ", "lambda ", "internal "}; dump (dumper::TREE) && dump ("Written:%d %sidentifier:%N", tag, kinds[code - tt_id], @@ -9961,8 +10086,11 @@ trees_out::tree_node (tree t) break; case VAR_DECL: - /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs. */ - gcc_checking_assert (!DECL_NAME (t) + /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs, + and internal vars are created by sanitizers and + __builtin_source_location. */ + gcc_checking_assert ((!DECL_NAME (t) + || IDENTIFIER_INTERNAL_P (DECL_NAME (t))) && DECL_ARTIFICIAL (t)); break; @@ -9971,7 +10099,18 @@ trees_out::tree_node (tree t) PARM_DECLS. It'd be nice if they had a distinguishing flag to double check. */ break; + + case TYPE_DECL: + /* Some parts of the compiler need internal struct types; + these types may not have an appropriate context to use. + Walk the whole type (including its definition) by value. */ + gcc_checking_assert (DECL_ARTIFICIAL (t) + && TYPE_ARTIFICIAL (TREE_TYPE (t)) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t)) + && !CLASS_TYPE_P (TREE_TYPE (t))); + break; } + mark_declaration (t, has_definition (t)); goto by_value; } } @@ -10108,6 +10247,17 @@ trees_in::tree_node (bool is_use) } break; + case tt_internal_id: + /* An internal label. */ + { + const char *prefix = str (); + res = generate_internal_label (prefix); + int tag = insert (res); + dump (dumper::TREE) + && dump ("Read internal identifier:%d %N", tag, res); + } + break; + case tt_typedef_type: res = tree_node (); if (res) @@ -10503,7 +10653,8 @@ trees_in::tree_node (bool is_use) res = lookup_field_ident (ctx, u ()); if (!res - || TREE_CODE (res) != FIELD_DECL + || (TREE_CODE (res) != FIELD_DECL + && TREE_CODE (res) != USING_DECL) || DECL_CONTEXT (res) != ctx) res = NULL_TREE; } @@ -11110,6 +11261,11 @@ trees_out::get_merge_kind (tree decl, depset *dep) return MK_local_friend; gcc_checking_assert (TYPE_P (ctx)); + + /* Internal-only types will not need to dedup their members. */ + if (!DECL_CONTEXT (TYPE_NAME (ctx))) + return MK_unique; + if (TREE_CODE (decl) == USING_DECL) return MK_field; @@ -11122,15 +11278,16 @@ trees_out::get_merge_kind (tree decl, depset *dep) return MK_named; } - if (!DECL_NAME (decl) - && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) - && !DECL_BIT_FIELD_REPRESENTATIVE (decl)) + if (walking_bit_field_unit) { /* The underlying storage unit for a bitfield. We do not need to dedup it, because it's only reachable through the bitfields it represents. And those are deduped. */ // FIXME: Is that assertion correct -- do we ever fish it // out and put it in an expr? + gcc_checking_assert (!DECL_NAME (decl) + && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)) + && !DECL_BIT_FIELD_REPRESENTATIVE (decl)); gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE ? TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) : TREE_CODE (TREE_TYPE (decl))) @@ -12090,6 +12247,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner)); } + // FIXME: do more precise errors at point of mismatch + const char *mismatch_msg = nullptr; if (TREE_CODE (d_inner) == FUNCTION_DECL) { tree e_ret = fndecl_declared_return_type (existing); @@ -12099,13 +12258,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner))) /* This has a recursive type that will compare different. */; else if (!same_type_p (d_ret, e_ret)) - goto mismatch; + { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); + goto mismatch; + } tree e_type = TREE_TYPE (e_inner); tree d_type = TREE_TYPE (d_inner); if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) - goto mismatch; + { + mismatch_msg = G_("conflicting language linkage for imported " + "declaration %#qD"); + goto mismatch; + } for (tree e_args = TYPE_ARG_TYPES (e_type), d_args = TYPE_ARG_TYPES (d_type); @@ -12113,10 +12279,18 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args)) { if (!(e_args && d_args)) - goto mismatch; + { + mismatch_msg = G_("conflicting argument list for imported " + "declaration %#qD"); + goto mismatch; + } if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args))) - goto mismatch; + { + mismatch_msg = G_("conflicting argument types for imported " + "declaration %#qD"); + goto mismatch; + } } /* If EXISTING has an undeduced or uninstantiated exception @@ -12147,9 +12321,14 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } } } - else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) + else if (!DECL_MAYBE_DELETED (d_inner) + && !DEFERRED_NOEXCEPT_SPEC_P (d_spec) && !comp_except_specs (d_spec, e_spec, ce_type)) - goto mismatch; + { + mismatch_msg = G_("conflicting %<noexcept%> specifier for " + "imported declaration %#qD"); + goto mismatch; + } /* Similarly if EXISTING has an undeduced return type, but DECL's is already deduced. */ @@ -12157,22 +12336,43 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) { dump (dumper::MERGE) && dump ("Propagating deduced return type to %N", existing); - FNDECL_USED_AUTO (e_inner) = true; + gcc_checking_assert (existing == e_inner); + FNDECL_USED_AUTO (existing) = true; DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type); TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type); } else if (type_uses_auto (d_ret) && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type))) - goto mismatch; + { + mismatch_msg = G_("conflicting deduced return type for " + "imported declaration %#qD"); + goto mismatch; + } /* Similarly if EXISTING has undeduced constexpr, but DECL's is already deduced. */ - if (DECL_MAYBE_DELETED (e_inner) && !DECL_MAYBE_DELETED (d_inner) - && DECL_DECLARED_CONSTEXPR_P (d_inner)) - DECL_DECLARED_CONSTEXPR_P (e_inner) = true; + if (DECL_DECLARED_CONSTEXPR_P (e_inner) + == DECL_DECLARED_CONSTEXPR_P (d_inner)) + /* Already matches. */; + else if (DECL_DECLARED_CONSTEXPR_P (d_inner) + && (DECL_MAYBE_DELETED (e_inner) + || decl_implicit_constexpr_p (d_inner))) + /* DECL was deduced, copy to EXISTING. */ + { + DECL_DECLARED_CONSTEXPR_P (e_inner) = true; + if (decl_implicit_constexpr_p (d_inner)) + DECL_LANG_SPECIFIC (e_inner)->u.fn.implicit_constexpr = true; + } else if (DECL_DECLARED_CONSTEXPR_P (e_inner) - != DECL_DECLARED_CONSTEXPR_P (d_inner)) - goto mismatch; + && (DECL_MAYBE_DELETED (d_inner) + || decl_implicit_constexpr_p (e_inner))) + /* EXISTING was deduced, leave it alone. */; + else + { + mismatch_msg = G_("conflicting %<constexpr%> for imported " + "declaration %#qD"); + goto mismatch; + } /* Don't synthesize a defaulted function if we're importing one we've already determined. */ @@ -12184,13 +12384,17 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) if (!DECL_ORIGINAL_TYPE (e_inner) || !same_type_p (DECL_ORIGINAL_TYPE (d_inner), DECL_ORIGINAL_TYPE (e_inner))) - goto mismatch; + { + mismatch_msg = G_("conflicting imported declaration %q#D"); + goto mismatch; + } } /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs here. I suspect the entities that directly do that are things that shouldn't go to duplicate_decls (FIELD_DECLs etc). */ else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); mismatch: if (DECL_IS_UNDECLARED_BUILTIN (existing)) /* Just like duplicate_decls, presum the user knows what @@ -12203,11 +12407,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) equality isn't feasible in general for local entities. */; else { - // FIXME:QOI Might be template specialization from a module, - // not necessarily global module + gcc_checking_assert (mismatch_msg); auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "conflicting global module declaration %#qD", decl); + error_at (DECL_SOURCE_LOCATION (decl), mismatch_msg, decl); inform (DECL_SOURCE_LOCATION (existing), "existing declaration %#qD", existing); return false; @@ -12604,7 +12806,11 @@ trees_out::write_function_def (tree decl) { unsigned flags = 0; - flags |= 1 * DECL_NOT_REALLY_EXTERN (decl); + /* Whether the importer should emit this definition, if used. */ + flags |= 1 * (DECL_NOT_REALLY_EXTERN (decl) + && (get_importer_interface (decl) + != importer_interface::external)); + if (f) { flags |= 2; @@ -14028,9 +14234,10 @@ depset::hash::make_dependency (tree decl, entity_kind ek) streaming the definition in such cases. */ dep->clear_flag_bit<DB_DEFN_BIT> (); - if (DECL_DECLARED_CONSTEXPR_P (decl)) - /* Also, a constexpr variable initialized to a TU-local - value is an exposure. */ + if (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_INLINE_VAR_P (decl)) + /* A constexpr variable initialized to a TU-local value, + or an inline value (PR c++/119996), is an exposure. */ dep->set_flag_bit<DB_EXPOSURE_BIT> (); } } @@ -14788,9 +14995,16 @@ depset::hash::find_dependencies (module_state *module) } walker.end (); + /* If we see either a class template or a deduction guide, make + sure to add all visible deduction guides. We need to check + both in case they have been added in separate modules, or + one is in the GMF and would have otherwise been discarded. */ if (!is_key_order () && DECL_CLASS_TEMPLATE_P (decl)) add_deduction_guides (decl); + if (!is_key_order () + && deduction_guide_p (decl)) + add_deduction_guides (TYPE_NAME (TREE_TYPE (TREE_TYPE (decl)))); if (!is_key_order () && TREE_CODE (decl) == TEMPLATE_DECL @@ -14991,12 +15205,24 @@ depset::hash::finalize_dependencies () break; } - if (!explained && VAR_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl)) + if (!explained + && VAR_P (decl) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_INLINE_VAR_P (decl))) { auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "%qD is declared %<constexpr%> and is initialized to " - "a TU-local value", decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD is declared %<constexpr%> and is initialized to " + "a TU-local value", decl); + else + { + /* This can only occur with references. */ + gcc_checking_assert (TYPE_REF_P (TREE_TYPE (decl))); + error_at (DECL_SOURCE_LOCATION (decl), + "%qD is a reference declared %<inline%> and is " + "constant-initialized to a TU-local value", decl); + } bool informed = is_tu_local_value (decl, DECL_INITIAL (decl), /*explain=*/true); gcc_checking_assert (informed); @@ -16787,11 +17013,15 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces, bytes_out sec (to); sec.begin (); + hash_map<tree, unsigned> ns_map; + for (unsigned ix = 0; ix != num; ix++) { depset *b = spaces[ix]; tree ns = b->get_entity (); + ns_map.put (ns, ix); + /* This could be an anonymous namespace even for a named module, since we can still emit no-linkage decls. */ gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL); @@ -16833,6 +17063,31 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces, } } + /* Now write exported using-directives, as a sequence of 1-origin indices in + the spaces array (not entity indices): First the using namespace, then the + used namespaces. And then a zero terminating the list. :: is + represented as index -1. */ + auto emit_one_ns = [&](unsigned ix, tree ns) { + for (auto udir: NAMESPACE_LEVEL (ns)->using_directives) + { + if (TREE_CODE (udir) != USING_DECL || !DECL_MODULE_EXPORT_P (udir)) + continue; + tree ns2 = USING_DECL_DECLS (udir); + dump() && dump ("Writing using-directive in %N for %N", + ns, ns2); + sec.u (ix); + sec.u (*ns_map.get (ns2) + 1); + } + }; + emit_one_ns (-1, global_namespace); + for (unsigned ix = 0; ix != num; ix++) + { + depset *b = spaces[ix]; + tree ns = b->get_entity (); + emit_one_ns (ix + 1, ns); + } + sec.u (0); + sec.end (to, to->name (MOD_SNAME_PFX ".nms"), crc_p); dump.outdent (); } @@ -16851,6 +17106,8 @@ module_state::read_namespaces (unsigned num) dump () && dump ("Reading namespaces"); dump.indent (); + tree *ns_map = XALLOCAVEC (tree, num); + for (unsigned ix = 0; ix != num; ix++) { unsigned entity_index = sec.u (); @@ -16912,6 +17169,8 @@ module_state::read_namespaces (unsigned num) DECL_ATTRIBUTES (inner) = tree_cons (get_identifier ("abi_tag"), tags, DECL_ATTRIBUTES (inner)); + ns_map[ix] = inner; + /* Install the namespace. */ (*entity_ary)[entity_lwm + entity_index] = inner; if (DECL_MODULE_IMPORT_P (inner)) @@ -16926,6 +17185,44 @@ module_state::read_namespaces (unsigned num) *slot = entity_lwm + entity_index; } } + + /* Read the exported using-directives. */ + while (unsigned ix = sec.u ()) + { + tree ns; + if (ix == (unsigned)-1) + ns = global_namespace; + else + { + if (--ix >= num) + { + sec.set_overrun (); + break; + } + ns = ns_map [ix]; + } + unsigned ix2 = sec.u (); + if (--ix2 >= num) + { + sec.set_overrun (); + break; + } + tree ns2 = ns_map [ix2]; + if (directness) + { + dump() && dump ("Reading using-directive in %N for %N", + ns, ns2); + /* In an export import this will mark the using-directive as + exported, so it will be emitted again. */ + add_using_namespace (ns, ns2); + } + else + /* Ignore using-directives from indirect imports, we only want them + from our own imports. */ + dump() && dump ("Ignoring using-directive in %N for %N", + ns, ns2); + } + dump.outdent (); if (!sec.end (from ())) return false; @@ -18018,6 +18315,168 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info, dump.outdent (); } +/* Return the prefix to use for dumping a #pragma diagnostic change to DK. */ + +static const char * +dk_string (diagnostic_t dk) +{ + gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND); + if (dk == DK_IGNORED) + /* diagnostic.def has an empty string for ignored. */ + return "ignored: "; + else + return get_diagnostic_kind_text (dk); +} + +/* Dump one #pragma GCC diagnostic entry. */ + +static bool +dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk) +{ + if (dk == DK_POP) + return dump (" Index %u: pop from %d", index, opt); + else + return dump (" Index %u: %s%s", index, dk_string (dk), + cl_options[opt].opt_text); +} + +/* Write out any #pragma GCC diagnostic info to the .dgc section. */ + +void +module_state::write_diagnostic_classification (elf_out *to, + diagnostic_context *dc, + unsigned *crc_p) +{ + auto &changes = dc->get_classification_history (); + + bytes_out sec (to); + if (sec.streaming_p ()) + { + sec.begin (); + dump () && dump ("Writing diagnostic change locations"); + dump.indent (); + } + + unsigned len = changes.length (); + + /* We don't want to write out any entries that came from one of our imports. + But then we need to adjust the total, and change DK_POP targets to match + the index in our actual output. So remember how many lines we had skipped + at each step, where -1 means this line itself is skipped. */ + int skips = 0; + auto_vec<int> skips_at (len); + skips_at.safe_grow (len); + + for (unsigned i = 0; i < len; ++i) + { + const auto &c = changes[i]; + skips_at[i] = skips; + if (linemap_location_from_module_p (line_table, c.location)) + { + ++skips; + skips_at[i] = -1; + continue; + } + } + + if (sec.streaming_p ()) + { + sec.u (len - skips); + dump () && dump ("Diagnostic changes: %u", len - skips); + } + + for (unsigned i = 0; i < len; ++i) + { + if (skips_at[i] == -1) + continue; + + const auto &c = changes[i]; + write_location (sec, c.location); + if (sec.streaming_p ()) + { + unsigned opt = c.option; + if (c.kind == DK_POP) + opt -= skips_at[opt]; + sec.u (opt); + sec.u (c.kind); + dump () && dump_dc_change (i - skips_at[i], opt, c.kind); + } + } + + if (sec.streaming_p ()) + { + sec.end (to, to->name (MOD_SNAME_PFX ".dgc"), crc_p); + dump.outdent (); + } +} + +/* Read any #pragma GCC diagnostic info from the .dgc section. */ + +bool +module_state::read_diagnostic_classification (diagnostic_context *dc) +{ + bytes_in sec; + + if (!sec.begin (loc, from (), MOD_SNAME_PFX ".dgc")) + return false; + + dump () && dump ("Reading diagnostic change locations"); + dump.indent (); + + unsigned len = sec.u (); + dump () && dump ("Diagnostic changes: %u", len); + + auto &changes = dc->get_classification_history (); + int offset = changes.length (); + changes.reserve (len + 1); + for (unsigned i = 0; i < len; ++i) + { + location_t loc = read_location (sec); + int opt = sec.u (); + diagnostic_t kind = (diagnostic_t) sec.u (); + if (kind == DK_POP) + /* For a pop, opt is the 'changes' index to return to. */ + opt += offset; + changes.quick_push ({ loc, opt, kind }); + dump () && dump_dc_change (changes.length () - 1, opt, kind); + } + + /* Did the import pop all its diagnostic changes? */ + bool last_was_reset = (len == 0); + if (len) + for (int i = changes.length () - 1; ; --i) + { + gcc_checking_assert (i >= offset); + + const auto &c = changes[i]; + if (c.kind != DK_POP) + break; + else if (c.option == offset) + { + last_was_reset = true; + break; + } + else + /* As in update_effective_level_from_pragmas, the loop will decrement + i so we actually jump to c.option - 1. */ + i = c.option; + } + if (!last_was_reset) + { + /* It didn't, so add a pop at its last location to avoid affecting later + imports. */ + location_t last_loc = ordinary_locs.first + ordinary_locs.second - 1; + changes.quick_push ({ last_loc, offset, DK_POP }); + dump () && dump (" Adding final pop from index %d", offset); + } + + dump.outdent (); + if (!sec.end (from ())) + return false; + + return true; +} + void module_state::write_macro_maps (elf_out *to, range_t &info, unsigned *crc_p) { @@ -19704,6 +20163,8 @@ module_state::write_begin (elf_out *to, cpp_reader *reader, } ool->qsort (ool_cmp); + write_diagnostic_classification (nullptr, global_dc, nullptr); + vec<cpp_hashnode *> *macros = nullptr; if (is_header ()) macros = prepare_macros (reader); @@ -19849,7 +20310,10 @@ module_state::write_begin (elf_out *to, cpp_reader *reader, /* Write the line maps. */ if (config.ordinary_locs) - write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc); + { + write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc); + write_diagnostic_classification (to, global_dc, &crc); + } if (config.macro_locs) write_macro_maps (to, map_info, &crc); @@ -19922,6 +20386,10 @@ module_state::read_initial (cpp_reader *reader) else if (!read_ordinary_maps (config.ordinary_locs, config.loc_range_bits)) ok = false; + if (ok && have_locs && config.ordinary_locs + && !read_diagnostic_classification (global_dc)) + ok = false; + /* Allocate the REMAP vector. */ slurp->alloc_remap (config.num_imports); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 1cd982e..9aa7c16 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -583,7 +583,7 @@ name_lookup::preserve_state () if (previous) { unsigned length = vec_safe_length (previous->scopes); - vec_safe_reserve (previous->scopes, length * 2); + vec_safe_reserve (previous->scopes, length); for (unsigned ix = length; ix--;) { tree decl = (*previous->scopes)[ix]; @@ -1049,7 +1049,7 @@ name_lookup::search_usings (tree scope) bool found = false; if (vec<tree, va_gc> *usings = NAMESPACE_LEVEL (scope)->using_directives) for (unsigned ix = usings->length (); ix--;) - found |= search_qualified ((*usings)[ix], true); + found |= search_qualified (strip_using_decl ((*usings)[ix]), true); /* Look in its inline children. */ if (vec<tree, va_gc> *inlinees = DECL_NAMESPACE_INLINEES (scope)) @@ -1121,7 +1121,7 @@ name_lookup::queue_usings (using_queue& queue, int depth, vec<tree, va_gc> *usin { if (usings) for (unsigned ix = usings->length (); ix--;) - queue_namespace (queue, depth, (*usings)[ix]); + queue_namespace (queue, depth, strip_using_decl ((*usings)[ix])); } /* Unqualified namespace lookup in SCOPE. @@ -4178,22 +4178,6 @@ mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *vec) return vslot; } -/* Retrieve the bindings for an existing mergeable entity in namespace - NS slot NAME. Returns NULL if no such bindings exists. */ - -static tree -get_mergeable_namespace_binding (tree ns, tree name, bool is_attached) -{ - tree *mslot = find_namespace_slot (ns, name, false); - if (!mslot || !*mslot || TREE_CODE (*mslot) != BINDING_VECTOR) - return NULL_TREE; - - tree *vslot = get_fixed_binding_slot - (mslot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, - false); - return vslot ? *vslot : NULL_TREE; -} - /* DECL is a new mergeable namespace-scope decl. Add it to the mergeable entities on GSLOT. */ @@ -4572,11 +4556,12 @@ lookup_imported_hidden_friend (tree friend_tmpl) || !DECL_MODULE_ENTITY_P (inner)) return NULL_TREE; + /* Load any templates matching FRIEND_TMPL from importers. */ lazy_load_pendings (friend_tmpl); - tree bind = get_mergeable_namespace_binding - (current_namespace, DECL_NAME (inner), DECL_MODULE_ATTACH_P (inner)); - if (!bind) + tree name = DECL_NAME (inner); + tree *slot = find_namespace_slot (current_namespace, name, false); + if (!slot || !*slot || TREE_CODE (*slot) != BINDING_VECTOR) return NULL_TREE; /* We're only interested in declarations attached to the same module @@ -4584,9 +4569,28 @@ lookup_imported_hidden_friend (tree friend_tmpl) int m = get_originating_module (friend_tmpl, /*global=-1*/true); gcc_assert (m != 0); + /* First check whether there's a reachable declaration attached to the module + we're looking for. */ + if (m > 0) + if (binding_slot *mslot = search_imported_binding_slot (slot, m)) + { + if (mslot->is_lazy ()) + lazy_load_binding (m, current_namespace, name, mslot); + for (ovl_iterator iter (*mslot); iter; ++iter) + if (DECL_CLASS_TEMPLATE_P (*iter)) + return *iter; + } + + /* Otherwise, look in the mergeable slots for this name, in case an importer + has already instantiated this declaration. */ + tree *vslot = get_fixed_binding_slot + (slot, name, m > 0 ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, false); + if (!vslot || !*vslot) + return NULL_TREE; + /* There should be at most one class template from the module we're looking for, return it. */ - for (ovl_iterator iter (bind); iter; ++iter) + for (ovl_iterator iter (*vslot); iter; ++iter) if (DECL_CLASS_TEMPLATE_P (*iter) && get_originating_module (*iter, true) == m) return *iter; @@ -6864,7 +6868,7 @@ using_directives_contain_std_p (vec<tree, va_gc> *usings) return false; for (unsigned ix = usings->length (); ix--;) - if ((*usings)[ix] == std_node) + if (strip_using_decl ((*usings)[ix]) == std_node) return true; return false; @@ -7084,13 +7088,16 @@ namespace_hints::convert_candidates_to_name_hint () /* Clean up CANDIDATES. */ m_candidates.release (); return name_hint (expr_to_string (candidate), - new show_candidate_location (m_loc, candidate)); + std::make_unique<show_candidate_location> (m_loc, + candidate)); } else if (m_candidates.length () > 1) /* If we have more than one candidate, issue a name_hint without a single "suggestion", but with a deferred diagnostic that lists the various candidates. This takes ownership of m_candidates. */ - return name_hint (NULL, new suggest_alternatives (m_loc, m_candidates)); + return name_hint (NULL, + std::make_unique<suggest_alternatives> (m_loc, + m_candidates)); /* Otherwise, m_candidates ought to be empty, so no cleanup is necessary. */ gcc_assert (m_candidates.length () == 0); @@ -7110,10 +7117,11 @@ name_hint namespace_hints::maybe_decorate_with_limit (name_hint hint) { if (m_limited) - return name_hint (hint.suggestion (), - new namespace_limit_reached (m_loc, m_limit, - m_name, - hint.take_deferred ())); + return name_hint + (hint.suggestion (), + std::make_unique<namespace_limit_reached> (m_loc, m_limit, + m_name, + hint.take_deferred ())); else return hint; } @@ -7190,10 +7198,11 @@ suggest_alternatives_for_1 (location_t location, tree name, diagnostic_option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) - return name_hint (nullptr, - new suggest_missing_option (location, - IDENTIFIER_POINTER (name), - option_id)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_option> (location, + IDENTIFIER_POINTER (name), + option_id)); /* Otherwise, consider misspellings. */ if (!suggest_misspellings) @@ -7321,8 +7330,9 @@ maybe_suggest_missing_std_header (location_t location, tree name) if (!header_hint) return name_hint (); - return name_hint (NULL, new missing_std_header (location, name_str, - header_hint)); + return name_hint (nullptr, + std::make_unique<missing_std_header> (location, name_str, + header_hint)); } /* Attempt to generate a name_hint that suggests a missing header file @@ -7704,12 +7714,12 @@ class macro_use_before_def : public deferred_diagnostic public: /* Factory function. Return a new macro_use_before_def instance if appropriate, or return NULL. */ - static macro_use_before_def * + static std::unique_ptr<macro_use_before_def> maybe_make (location_t use_loc, cpp_hashnode *macro) { location_t def_loc = cpp_macro_definition_location (macro); if (def_loc == UNKNOWN_LOCATION) - return NULL; + return nullptr; /* We only want to issue a note if the macro was used *before* it was defined. @@ -7717,12 +7727,11 @@ class macro_use_before_def : public deferred_diagnostic used, leaving it unexpanded (e.g. by using the wrong argument count). */ if (!linemap_location_before_p (line_table, use_loc, def_loc)) - return NULL; + return nullptr; - return new macro_use_before_def (use_loc, macro); + return std::make_unique<macro_use_before_def> (use_loc, macro); } - private: /* Ctor. LOC is the location of the usage. MACRO is the macro that was used. */ macro_use_before_def (location_t loc, cpp_hashnode *macro) @@ -7789,10 +7798,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc) const char *header_hint = get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name)); if (header_hint) - return name_hint (NULL, - new suggest_missing_header (loc, - IDENTIFIER_POINTER (name), - header_hint)); + return name_hint + (nullptr, + std::make_unique<suggest_missing_header> (loc, + IDENTIFIER_POINTER (name), + header_hint)); best_match <tree, const char *> bm (name); @@ -8933,9 +8943,27 @@ add_using_namespace (vec<tree, va_gc> *&usings, tree target) if ((*usings)[ix] == target) return; + if (modules_p ()) + { + tree u = build_lang_decl (USING_DECL, NULL_TREE, NULL_TREE); + USING_DECL_DECLS (u) = target; + DECL_MODULE_EXPORT_P (u) = module_exporting_p (); + DECL_MODULE_PURVIEW_P (u) = module_purview_p (); + target = u; + } vec_safe_push (usings, target); } +/* Convenience overload for the above, taking the user as its first + parameter. */ + +void +add_using_namespace (tree ns, tree target) +{ + add_using_namespace (NAMESPACE_LEVEL (ns)->using_directives, + ORIGINAL_NAMESPACE (target)); +} + /* Tell the debug system of a using directive. */ static void diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index f1596c6..2fa736b 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -462,6 +462,7 @@ extern cxx_binding *outer_binding (tree, cxx_binding *, bool); extern void cp_emit_debug_info_for_using (tree, tree); extern void finish_nonmember_using_decl (tree scope, tree name); +extern void add_using_namespace (tree, tree); extern void finish_using_directive (tree target, tree attribs); void push_local_extern_decl_alias (tree decl); extern tree pushdecl (tree, bool hiding = false); @@ -500,6 +501,10 @@ enum WMB_Flags WMB_Hidden = 1 << 3, WMB_Purview = 1 << 4, }; +inline WMB_Flags operator|(WMB_Flags x, WMB_Flags y) +{ return WMB_Flags(+x|y); } +inline WMB_Flags& operator|=(WMB_Flags& x, WMB_Flags y) +{ return x = x|y; } extern unsigned walk_module_binding (tree binding, bitmap partitions, bool (*)(tree decl, WMB_Flags, void *data), diff --git a/gcc/cp/optimize.cc b/gcc/cp/optimize.cc index 6f9a77f..fc4d6c2 100644 --- a/gcc/cp/optimize.cc +++ b/gcc/cp/optimize.cc @@ -309,8 +309,8 @@ maybe_thunk_body (tree fn, bool force) defer_mangling_aliases = save_defer_mangling_aliases; cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group); cgraph_node::get_create (fns[1])->add_to_same_comdat_group - (cgraph_node::get_create (fns[0])); - symtab_node::get (fn)->add_to_same_comdat_group + (cgraph_node::get (fns[0])); + symtab_node::get_create (fn)->add_to_same_comdat_group (symtab_node::get (fns[0])); if (fns[2]) /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 812a7c5..b1626ac 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "contracts.h" #include "bitmap.h" #include "builtins.h" +#include "analyzer/analyzer-language.h" /* The lexer. */ @@ -286,6 +287,37 @@ static FILE *cp_lexer_debug_stream; sizeof, typeof, or alignof. */ int cp_unevaluated_operand; +#if ENABLE_ANALYZER + +namespace ana { + +/* Concrete implementation of ana::translation_unit for the C++ frontend. */ + +class cp_translation_unit : public translation_unit +{ +public: + tree lookup_constant_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } + + tree + lookup_type_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } + + tree + lookup_global_var_by_id (tree /*id*/) const final override + { + return NULL_TREE; + } +}; + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ + /* Dump up to NUM tokens in BUFFER to FILE starting with token START_TOKEN. If START_TOKEN is NULL, the dump starts with the first token in BUFFER. If NUM is 0, dump all the tokens. If @@ -3434,9 +3466,11 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, const char *header_hint = get_cp_stdlib_header_for_string_macro_name (token_name); if (header_hint != NULL) - h = name_hint (NULL, new suggest_missing_header (token->location, - token_name, - header_hint)); + h = name_hint + (nullptr, + std::make_unique<suggest_missing_header> (token->location, + token_name, + header_hint)); } /* Actually emit the error. */ @@ -5469,6 +5503,14 @@ cp_parser_translation_unit (cp_parser* parser) cp_parser_toplevel_declaration (parser); } +#if ENABLE_ANALYZER + if (flag_analyzer) + { + ana::cp_translation_unit tu; + ana::on_finish_translation_unit (tu); + } +#endif + /* Get rid of the token array; we don't need it any more. */ cp_lexer_destroy (parser->lexer); parser->lexer = NULL; @@ -10793,6 +10835,14 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, goto pop; } + /* If we skipped build_cplus_new in build_cxx_call because of decltype_p, + call it now that we know current.lhs is a subexpression. */ + if (decltype_p && !processing_template_decl + && TREE_CODE (current.lhs) == CALL_EXPR + && CLASS_TYPE_P (TREE_TYPE (current.lhs))) + current.lhs = build_cplus_new (TREE_TYPE (current.lhs), current.lhs, + tf_warning_or_error); + get_rhs: current.tree_type = binops_by_token[token->type].tree_type; current.loc = token->location; @@ -15389,11 +15439,12 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) case RID_GOTO: if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && maybe_constexpr_fn (current_function_decl) && cxx_dialect < cxx23) { - error ("%<goto%> in %<constexpr%> function only available with " - "%<-std=c++23%> or %<-std=gnu++23%>"); + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error ("%<goto%> in %<constexpr%> function only available with " + "%<-std=c++23%> or %<-std=gnu++23%>"); cp_function_chain->invalid_constexpr = true; } @@ -15785,7 +15836,13 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, " must not be from header inclusion"); } + auto mk = module_kind; + if (exporting) + module_kind |= MK_EXPORTING; + import_module (mod, token->location, exporting, attrs, parse_in); + + module_kind = mk; } } @@ -30372,6 +30429,9 @@ cp_parser_asm_operand_list (cp_parser* parser) parens.require_open (parser); /* Parse the expression. */ tree expression = cp_parser_expression (parser); + if (check_for_bare_parameter_packs (expression)) + expression = error_mark_node; + /* Look for the `)'. */ parens.require_close (parser); @@ -33634,6 +33694,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, = parser->num_template_parameter_lists; parser->num_template_parameter_lists = 0; + int errs = errorcount + sorrycount; + /* If the next token is `try', `__transaction_atomic', or `__transaction_relaxed`, then we are looking at either function-try-block or function-transaction-block. Note that all of these include the @@ -33653,6 +33715,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, fn = finish_function (inline_p); check_module_decl_linkage (fn); + if ((errorcount + sorrycount) > errs) + DECL_STRUCT_FUNCTION (fn)->language->erroneous = true; + if (modules_p () && !inline_p && TYPE_P (DECL_CONTEXT (fn)) @@ -42370,13 +42435,13 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, map ( [map-type-modifier[,] ...] map-kind: variable-list ) map-type-modifier: - always | close */ + always | close | mapper ( mapper-name ) */ static tree -cp_parser_omp_clause_map (cp_parser *parser, tree list) +cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) { tree nlist, c; - enum gomp_map_kind kind = GOMP_MAP_TOFROM; + enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; @@ -42394,12 +42459,17 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) pos++; + else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type + == CPP_OPEN_PAREN) + pos = cp_parser_skip_balanced_tokens (parser, pos + 1); pos++; } bool always_modifier = false; bool close_modifier = false; bool present_modifier = false; + bool mapper_modifier = false; + tree mapper_name = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { cp_token *tok = cp_lexer_peek_token (parser->lexer); @@ -42422,6 +42492,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } always_modifier = true; + cp_lexer_consume_token (parser->lexer); } else if (strcmp ("close", p) == 0) { @@ -42435,6 +42506,77 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } close_modifier = true; + cp_lexer_consume_token (parser->lexer); + } + else if (strcmp ("mapper", p) == 0) + { + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (mapper_modifier) + { + cp_parser_error (parser, "too many %<mapper%> modifiers"); + /* Assume it's a well-formed mapper modifier, even if it + seems to be in the wrong place. */ + cp_lexer_consume_token (parser->lexer); + parens.require_close (parser); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + return list; + } + + tok = cp_lexer_peek_token (parser->lexer); + switch (tok->type) + { + case CPP_NAME: + { + cp_expr e = cp_parser_identifier (parser); + if (e != error_mark_node) + mapper_name = e; + else + goto err; + if (declare_mapper_p) + { + error_at (e.get_location (), + "in %<declare mapper%> directives, parameter " + "to %<mapper%> modifier must be %<default%>"); + } + } + break; + + case CPP_KEYWORD: + if (tok->keyword == RID_DEFAULT) + { + cp_lexer_consume_token (parser->lexer); + break; + } + /* Fallthrough. */ + + default: + err: + cp_parser_error (parser, + "expected identifier or %<default%>"); + return list; + } + + if (!parens.require_close (parser)) + { + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + return list; + } + + mapper_modifier = true; + pos += 3; + } } else if (strcmp ("present", p) == 0) { @@ -42448,19 +42590,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } present_modifier = true; - } + cp_lexer_consume_token (parser->lexer); + } else { - cp_parser_error (parser, "%<map%> clause with map-type modifier other" - " than %<always%>, %<close%> or %<present%>"); + cp_parser_error (parser, "%<map%> clause with map-type modifier " + "other than %<always%>, %<close%>, " + "%<mapper%> or %<present%>"); cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); return list; } - - cp_lexer_consume_token (parser->lexer); } if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) @@ -42516,8 +42658,30 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) NULL, true); finish_scope (); + tree last_new = NULL_TREE; + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + last_new = c; + } + + if (mapper_name) + { + tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = mapper_name; + OMP_CLAUSE_CHAIN (name) = nlist; + nlist = name; + + gcc_assert (last_new); + + name = build_omp_clause (input_location, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME); + OMP_CLAUSE_DECL (name) = null_pointer_node; + OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new); + OMP_CLAUSE_CHAIN (last_new) = name; + } return nlist; } @@ -43845,7 +44009,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, c_name = "detach"; break; case PRAGMA_OMP_CLAUSE_MAP: - clauses = cp_parser_omp_clause_map (parser, clauses); + clauses = cp_parser_omp_clause_map (parser, clauses, + /*mapper=*/false); c_name = "map"; break; case PRAGMA_OMP_CLAUSE_DEVICE: @@ -48851,6 +49016,8 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = nc; } + if (!processing_template_decl) + clauses = c_omp_instantiate_mappers (clauses); clauses = finish_omp_clauses (clauses, C_ORT_OMP_TARGET); c_omp_adjust_map_clauses (clauses, true); @@ -49545,7 +49712,8 @@ cp_parser_oacc_update (cp_parser *parser, cp_token *pragma_tok) */ #define OACC_WAIT_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC)) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF)) static tree cp_parser_oacc_wait (cp_parser *parser, cp_token *pragma_tok) @@ -49830,12 +49998,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set, && !value_dependent_expression_p (t)) { t = fold_non_dependent_expr (t); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - error_at (token->location, - "property must be integer expression"); - return error_mark_node; + t = maybe_convert_cond (t); + if (t == error_mark_node) + return error_mark_node; + } + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } } + if (!processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); } properties = make_trait_property (NULL_TREE, t, properties); break; @@ -51404,7 +51585,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, { error_at (match_loc, "too many %<otherwise%> or %<default%> " "clauses in %<metadirective%>"); - cp_parser_skip_to_end_of_block_or_statement (parser, true); goto fail; } else @@ -51414,14 +51594,12 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, { error_at (match_loc, "%<otherwise%> or %<default%> clause " "must appear last in %<metadirective%>"); - cp_parser_skip_to_end_of_block_or_statement (parser, true); goto fail; } if (!default_p && strcmp (p, "when") != 0) { error_at (match_loc, "%qs is not valid for %qs", p, "metadirective"); - cp_parser_skip_to_end_of_block_or_statement (parser, true); goto fail; } @@ -51490,7 +51668,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, if (i == 0) { error_at (loc, "expected directive name"); - cp_parser_skip_to_end_of_block_or_statement (parser, true); goto fail; } @@ -51563,7 +51740,10 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, goto add; case CPP_CLOSE_PAREN: if (nesting_depth-- == 0) - break; + { + cp_lexer_consume_token (parser->lexer); + break; + } goto add; default: add: @@ -51575,8 +51755,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, break; } - cp_lexer_consume_token (parser->lexer); - if (!skip) { cp_token eol_token = {}; @@ -51708,11 +51886,8 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok, return; fail: - /* Skip the metadirective pragma. */ + /* Skip the metadirective pragma. Do not skip the metadirective body. */ cp_parser_skip_to_pragma_eol (parser, pragma_tok); - - /* Skip the metadirective body. */ - cp_parser_skip_to_end_of_block_or_statement (parser, true); } @@ -52131,6 +52306,175 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, obstack_free (&declarator_obstack, p); } +/* OpenMP 5.0 + #pragma omp declare mapper([mapper-identifier:]type var) \ + [clause[[,] clause] ... ] new-line */ + +static void +cp_parser_omp_declare_mapper (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context) +{ + cp_token *token = NULL; + tree type = NULL_TREE, vardecl = NULL_TREE, block = NULL_TREE; + bool block_scope = false; + /* Don't create location wrapper nodes within "declare mapper" + directives. */ + auto_suppress_location_wrappers sentinel; + tree mapper_name = NULL_TREE; + tree mapper_id, id, placeholder, mapper, maplist = NULL_TREE; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + goto fail; + + if (current_function_decl) + block_scope = true; + + token = cp_lexer_peek_token (parser->lexer); + + if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + switch (token->type) + { + case CPP_NAME: + { + cp_expr e = cp_parser_identifier (parser); + if (e != error_mark_node) + mapper_name = e; + else + goto fail; + } + break; + + case CPP_KEYWORD: + if (token->keyword == RID_DEFAULT) + { + mapper_name = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + break; + } + /* Fallthrough. */ + + default: + cp_parser_error (parser, "expected identifier or %<default%>"); + } + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto fail; + } + + { + const char *saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined within %<declare mapper%>"); + type_id_in_expr_sentinel s (parser); + type = cp_parser_type_id (parser); + parser->type_definition_forbidden_message = saved_message; + } + + if (type == error_mark_node) + goto fail; + if (dependent_type_p (type)) + mapper_id = omp_mapper_id (mapper_name, NULL_TREE); + else + mapper_id = omp_mapper_id (mapper_name, type); + + vardecl = build_lang_decl (VAR_DECL, mapper_id, type); + DECL_ARTIFICIAL (vardecl) = 1; + TREE_STATIC (vardecl) = 1; + TREE_PUBLIC (vardecl) = 0; + DECL_EXTERNAL (vardecl) = 0; + DECL_DECLARED_CONSTEXPR_P (vardecl) = 1; + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (vardecl) = 1; + DECL_OMP_DECLARE_MAPPER_P (vardecl) = 1; + + keep_next_level (true); + block = begin_omp_structured_block (); + + if (block_scope) + DECL_CONTEXT (vardecl) = current_function_decl; + else if (current_class_type) + DECL_CONTEXT (vardecl) = current_class_type; + else + DECL_CONTEXT (vardecl) = current_namespace; + + if (processing_template_decl) + vardecl = push_template_decl (vardecl); + + if ((id = cp_parser_declarator_id (parser, false)) == error_mark_node) + goto fail; + + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + finish_omp_structured_block (block); + goto fail; + } + + placeholder = build_lang_decl (VAR_DECL, id, type); + DECL_CONTEXT (placeholder) = DECL_CONTEXT (vardecl); + if (processing_template_decl) + placeholder = push_template_decl (placeholder); + pushdecl (placeholder); + cp_finish_decl (placeholder, NULL_TREE, 0, NULL_TREE, 0); + DECL_ARTIFICIAL (placeholder) = 1; + TREE_USED (placeholder) = 1; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser); + if (c_kind != PRAGMA_OMP_CLAUSE_MAP) + { + if (c_kind != PRAGMA_OMP_CLAUSE_NONE) + cp_parser_error (parser, "unexpected clause"); + finish_omp_structured_block (block); + goto fail; + } + maplist = cp_parser_omp_clause_map (parser, maplist, /*mapper=*/true); + if (maplist == NULL_TREE) + break; + } + + if (maplist == NULL_TREE) + { + cp_parser_error (parser, "missing %<map%> clause"); + finish_omp_structured_block (block); + goto fail; + } + + mapper = make_node (OMP_DECLARE_MAPPER); + TREE_TYPE (mapper) = type; + OMP_DECLARE_MAPPER_ID (mapper) = mapper_name; + OMP_DECLARE_MAPPER_DECL (mapper) = placeholder; + OMP_DECLARE_MAPPER_CLAUSES (mapper) = maplist; + + finish_omp_structured_block (block); + + DECL_INITIAL (vardecl) = mapper; + + if (current_class_type) + { + if (processing_template_decl) + { + retrofit_lang_decl (vardecl); + SET_DECL_VAR_DECLARED_INLINE_P (vardecl); + } + finish_static_data_member_decl (vardecl, mapper, + /*init_const_expr_p=*/true, NULL_TREE, 0); + finish_member_declaration (vardecl); + } + else if (processing_template_decl && block_scope) + add_decl_expr (vardecl); + else + pushdecl (vardecl); + + cp_check_omp_declare_mapper (vardecl); + + cp_parser_require_pragma_eol (parser, pragma_tok); + return; + +fail: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + /* OpenMP 4.0 #pragma omp declare simd declare-simd-clauses[optseq] new-line #pragma omp declare reduction (reduction-id : typename-list : expression) \ @@ -52175,6 +52519,12 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, context); return false; } + if (strcmp (p, "mapper") == 0) + { + cp_lexer_consume_token (parser->lexer); + cp_parser_omp_declare_mapper (parser, pragma_tok, context); + return false; + } if (!flag_openmp) /* flag_openmp_simd */ { cp_parser_skip_to_pragma_eol (parser, pragma_tok); @@ -52188,7 +52538,7 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, } } cp_parser_error (parser, "expected %<simd%>, %<reduction%>, " - "%<target%> or %<variant%>"); + "%<target%>, %<mapper%> or %<variant%>"); cp_parser_require_pragma_eol (parser, pragma_tok); return false; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 95b89f12..3362a6f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -202,7 +202,6 @@ static tree for_each_template_parm_r (tree *, int *, void *); static tree copy_default_args_to_explicit_spec_1 (tree, tree); static void copy_default_args_to_explicit_spec (tree); static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t); -static bool dependent_template_arg_p (tree); static bool dependent_type_p_r (tree); static tree tsubst_stmt (tree, tree, tsubst_flags_t, tree); static tree tsubst_decl (tree, tree, tsubst_flags_t, bool = true); @@ -7492,8 +7491,13 @@ get_template_parm_object (tree expr, tree name, bool check_init/*=true*/) { /* The EXPR is the already processed initializer, set it on the NTTP object now so that cp_finish_decl doesn't do it again later. */ + gcc_checking_assert (reduced_constant_expression_p (expr)); DECL_INITIAL (decl) = expr; - DECL_INITIALIZED_P (decl) = 1; + DECL_INITIALIZED_P (decl) = true; + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; + /* FIXME setting TREE_CONSTANT on refs breaks the back end. */ + if (!TYPE_REF_P (type)) + TREE_CONSTANT (decl) = true; } pushdecl_top_level_and_finish (decl, expr); @@ -10047,15 +10051,20 @@ tsubst_entering_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl) D1 is the PTYPENAME terminal, and ARGLIST is the list of arguments. + If D1 is an identifier and CONTEXT is non-NULL, then the lookup is + carried out in CONTEXT. Currently, only namespaces are supported for + CONTEXT. + + If D1 is an identifier and CONTEXT is NULL, the lookup is performed + in the innermost non-namespace binding. + + Otherwise CONTEXT is ignored and no lookup is carried out. + IN_DECL, if non-NULL, is the template declaration we are trying to instantiate. Issue error and warning messages under control of COMPLAIN. - If the template class is really a local class in a template - function, then the FUNCTION_CONTEXT is the function in which it is - being instantiated. - ??? Note that this function is currently called *twice* for each template-id: the first time from the parser, while creating the incomplete type (finish_template_type), and the second type during the @@ -10074,20 +10083,23 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context, spec_entry **slot; spec_entry *entry; - if (identifier_p (d1)) + if (identifier_p (d1) && context) + { + gcc_checking_assert (TREE_CODE (context) == NAMESPACE_DECL); + push_decl_namespace (context); + templ = lookup_name (d1, LOOK_where::NAMESPACE, LOOK_want::NORMAL); + pop_decl_namespace (); + } + else if (identifier_p (d1)) { tree value = innermost_non_namespace_value (d1); if (value && DECL_TEMPLATE_TEMPLATE_PARM_P (value)) templ = value; else - { - if (context) - push_decl_namespace (context); + { templ = lookup_name (d1); templ = maybe_get_template_decl_from_type_decl (templ); - if (context) - pop_decl_namespace (); - } + } } else if (TREE_CODE (d1) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (d1))) { @@ -11117,6 +11129,18 @@ any_template_parm_r (tree t, void *data) case LAMBDA_EXPR: { + /* TREE_STATIC on LAMBDA_EXPR_EXTRA_ARGS means a full set of + arguments, so we can just look there; they will replace + any template parms in the rest of the LAMBDA_EXPR. */ + if (tree args = LAMBDA_EXPR_EXTRA_ARGS (t)) + { + WALK_SUBTREE (args); + /* Without TREE_STATIC the args are just outer levels, so we'd + still need to look through the lambda for just inner + parameters. Hopefully that's not necessary. */ + gcc_checking_assert (TREE_STATIC (args)); + return 0; + } /* Look in the parms and body. */ tree fn = lambda_function (t); WALK_SUBTREE (TREE_TYPE (fn)); @@ -11361,6 +11385,7 @@ limit_bad_template_recursion (tree decl) static int tinst_depth; extern int max_tinst_depth; int depth_reached; +int tinst_dump_id; static GTY(()) struct tinst_level *last_error_tinst_level; @@ -11406,12 +11431,47 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) new_level->targs = targs; new_level->locus = loc; new_level->errors = errorcount + sorrycount; + new_level->had_errors = false; new_level->next = NULL; new_level->refcount = 0; new_level->path = new_level->visible = nullptr; set_refcount_ptr (new_level->next, current_tinst_level); set_refcount_ptr (current_tinst_level, new_level); + if (cxx_dump_pretty_printer pp {tinst_dump_id}) + { +#if __GNUC__ >= 10 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-diag" +#endif + bool list_p = new_level->list_p (); + if (list_p && !pp.has_flag (TDF_DETAILS)) + /* Skip non-instantiations unless -details. */; + else + { + if (tinst_depth == 0) + pp_newline (&pp); + if (loc && pp.has_flag (TDF_LINENO)) + { + for (int i = 0; i < tinst_depth; ++i) + pp_space (&pp); + const expanded_location el = expand_location (loc); + pp_printf (&pp, "%s:%d:%d", el.file, el.line, el.column); + pp_newline (&pp); + } + for (int i = 0; i < tinst_depth; ++i) + pp_space (&pp); + if (list_p) + pp_printf (&pp, "S %S", new_level->get_node ()); + else + pp_printf (&pp, "I %D", tldcl); + pp_newline (&pp); + } +#if __GNUC__ >= 10 +#pragma GCC diagnostic pop +#endif + } + ++tinst_depth; if (GATHER_STATISTICS && (tinst_depth > depth_reached)) depth_reached = tinst_depth; @@ -11456,10 +11516,27 @@ pop_tinst_level (void) /* Restore the filename and line number stashed away when we started this instantiation. */ input_location = current_tinst_level->locus; + if (unsigned errs = errorcount + sorrycount) + if (errs > current_tinst_level->errors) + current_tinst_level->had_errors = true; set_refcount_ptr (current_tinst_level, current_tinst_level->next); --tinst_depth; } +/* True if the instantiation represented by LEVEL is complete. */ + +static bool +tinst_complete_p (struct tinst_level *level) +{ + gcc_assert (!level->list_p ()); + tree node = level->get_node (); + if (TYPE_P (node)) + return COMPLETE_TYPE_P (node); + else + return (DECL_TEMPLATE_INSTANTIATED (node) + || DECL_TEMPLATE_SPECIALIZATION (node)); +} + /* We're instantiating a deferred template; restore the template instantiation context in which the instantiation was requested, which is one step out from LEVEL. Return the corresponding DECL or TYPE. */ @@ -11475,9 +11552,41 @@ reopen_tinst_level (struct tinst_level *level) set_refcount_ptr (current_tinst_level, level); pop_tinst_level (); - if (current_tinst_level) + if (current_tinst_level && !current_tinst_level->had_errors) current_tinst_level->errors = errorcount+sorrycount; + if (cxx_dump_pretty_printer pp {tinst_dump_id}) + { +#if __GNUC__ >= 10 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-diag" +#endif + /* Dump the reopened instantiation context. */ + t = current_tinst_level; + if (!pp.has_flag (TDF_DETAILS)) + /* Skip non-instantiations unless -details. */ + while (t && t->list_p ()) + t = t->next; + if (t) + { + static tree last_ctx = NULL_TREE; + tree ctx = t->get_node (); + if (ctx != last_ctx) + { + last_ctx = ctx; + pp_newline (&pp); + if (t->list_p ()) + pp_printf (&pp, "RS %S", ctx); + else + pp_printf (&pp, "RI %D", ctx); + pp_newline (&pp); + } + } +#if __GNUC__ >= 10 +#pragma GCC diagnostic pop +#endif + } + tree decl = level->maybe_get_node (); if (decl && modules_p ()) { @@ -11760,6 +11869,10 @@ tsubst_friend_function (tree decl, tree args) elt.args = DECL_TI_ARGS (spec); elt.spec = NULL_TREE; + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (DECL_TI_ARGS (spec)) + && !is_specialization_of_friend (spec, new_template)) + continue; + decl_specializations->remove_elt (&elt); tree& spec_args = DECL_TI_ARGS (spec); @@ -12413,6 +12526,8 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); + auto o6 = make_temp_override (target_option_current_node, + target_option_default_node); cplus_decl_attributes (decl_p, late_attrs, attr_flags); @@ -13736,11 +13851,12 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) inst = local; /* else inst is already a full instantiation of the pack. */ register_local_specialization (inst, gen); + if (is_normal_capture_proxy (gen)) + register_local_specialization (inst, DECL_CAPTURED_VARIABLE (gen)); } gcc_assert (!TREE_PURPOSE (extra)); extra = TREE_VALUE (extra); } - gcc_checking_assert (TREE_STATIC (extra) == uses_template_parms (extra)); if (TREE_STATIC (extra)) /* This is a partial substitution into e.g. a requires-expr or lambda-expr inside a default template argument; we expect 'extra' to be a full set @@ -14874,6 +14990,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t)) parms = DECL_CHAIN (parms); parms = tsubst (parms, args, complain, t); + if (parms == error_mark_node) + return error_mark_node; for (tree parm = parms; parm; parm = DECL_CHAIN (parm)) DECL_CONTEXT (parm) = r; if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t)) @@ -15446,6 +15564,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, /* We're dealing with a normal parameter. */ type = tsubst (TREE_TYPE (t), args, complain, in_decl); + if (type == error_mark_node && !(complain & tf_error)) + RETURN (error_mark_node); + type = type_decays_to (type); TREE_TYPE (r) = type; cp_apply_type_quals_to_decl (cp_type_quals (type), r); @@ -15483,8 +15604,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, /* If cp_unevaluated_operand is set, we're just looking for a single dummy parameter, so don't keep going. */ if (DECL_CHAIN (t) && !cp_unevaluated_operand) - DECL_CHAIN (r) = tsubst (DECL_CHAIN (t), args, - complain, DECL_CHAIN (t)); + { + tree chain = tsubst (DECL_CHAIN (t), args, + complain, DECL_CHAIN (t)); + if (chain == error_mark_node) + RETURN (error_mark_node); + DECL_CHAIN (r) = chain; + } /* FIRST_R contains the start of the chain we've built. */ r = first_r; @@ -15880,7 +16006,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); - if ((!local_p || TREE_STATIC (t)) && DECL_SECTION_NAME (t)) + if ((!local_p || TREE_STATIC (t)) + && !(flag_openmp && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t)) + && DECL_SECTION_NAME (t)) set_decl_section_name (r, t); } @@ -15932,6 +16061,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (r)); } + if (flag_openmp + && VAR_P (t) + && DECL_LANG_SPECIFIC (t) + && DECL_OMP_DECLARE_MAPPER_P (t) + && strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL) + DECL_NAME (r) = omp_mapper_id (DECL_NAME (t), TREE_TYPE (r)); + layout_decl (r, 0); } break; @@ -17158,18 +17294,24 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) case UNBOUND_CLASS_TEMPLATE: { - ++processing_template_decl; - tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args, - complain, in_decl); - --processing_template_decl; tree name = TYPE_IDENTIFIER (t); + if (name == error_mark_node) + return error_mark_node; + tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t)); + parm_list = tsubst_template_parms (parm_list, args, complain); + if (parm_list == error_mark_node) + return error_mark_node; - if (ctx == error_mark_node || name == error_mark_node) + if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1) + ++processing_template_decl; + tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args, + complain, in_decl); + if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1) + --processing_template_decl; + if (ctx == error_mark_node) return error_mark_node; - if (parm_list) - parm_list = tsubst_template_parms (parm_list, args, complain); return make_unbound_class_template (ctx, name, parm_list, complain); } @@ -17443,10 +17585,18 @@ tsubst_baselink (tree baselink, tree object_type, if (!baselink) { - if ((complain & tf_error) - && constructor_name_p (name, qualifying_scope)) - error ("cannot call constructor %<%T::%D%> directly", - qualifying_scope, name); + if (complain & tf_error) + { + if (constructor_name_p (name, qualifying_scope)) + error ("cannot call constructor %<%T::%D%> directly", + qualifying_scope, name); + else + /* Lookup succeeded at parse time, but failed during + instantiation; must be because we're trying to refer to it + while forming its declaration (c++/120204). */ + error ("declaration of %<%T::%D%> depends on itself", + qualifying_scope, name); + } return error_mark_node; } @@ -18190,8 +18340,10 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, } new_clauses = nreverse (new_clauses); - if (ort != C_ORT_OMP_DECLARE_SIMD) + if (ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_OMP_DECLARE_MAPPER) { + if (ort == C_ORT_OMP_TARGET) + new_clauses = c_omp_instantiate_mappers (new_clauses); new_clauses = finish_omp_clauses (new_clauses, ort); if (linear_no_step) for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc)) @@ -18245,7 +18397,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, } } - switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type) + enum omp_tp_type property_kind + = omp_ts_map[OMP_TS_CODE (sel)].tp_type; + switch (property_kind) { case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: @@ -18253,12 +18407,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, args, complain, in_decl); t = fold_non_dependent_expr (t); if (!value_dependent_expression_p (t) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (cp_expr_loc_or_input_loc (t), - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, NULL_TREE); + && !type_dependent_expression_p (t)) + { + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + t = maybe_convert_cond (t); + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (cp_expr_loc_or_input_loc (t), + "property must be integer expression"); + t = error_mark_node; + } + } + } + if (t != error_mark_node + && !processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + properties = make_trait_property (NULL_TREE, t, NULL_TREE); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD) @@ -19911,6 +20079,22 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; } + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); + } + case TRANSACTION_EXPR: { int flags = 0; @@ -20970,6 +21154,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RETURN (build_omp_array_section (EXPR_LOCATION (t), op0, op1, op2)); } + case OMP_DECLARE_MAPPER: + { + t = copy_node (t); + + tree decl = OMP_DECLARE_MAPPER_DECL (t); + DECL_OMP_DECLARE_MAPPER_P (decl) = 1; + decl = tsubst (decl, args, complain, in_decl); + tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t); + clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args, + complain, in_decl); + TREE_TYPE (t) = type; + OMP_DECLARE_MAPPER_DECL (t) = decl; + OMP_DECLARE_MAPPER_CLAUSES (t) = clauses; + RETURN (t); + } + case SIZEOF_EXPR: if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)) || ARGUMENT_PACK_P (TREE_OPERAND (t, 0))) @@ -21301,13 +21502,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Avoid error about taking the address of a constructor. */ function = TREE_OPERAND (function, 0); - tsubst_flags_t subcomplain = complain; - if (koenig_p && TREE_CODE (function) == FUNCTION_DECL) - /* When KOENIG_P, we don't want to mark_used the callee before - augmenting the overload set via ADL, so during this initial - substitution we disable mark_used by setting tf_conv (68942). */ - subcomplain |= tf_conv; - function = tsubst_expr (function, args, subcomplain, in_decl); + function = tsubst_expr (function, args, complain, in_decl); if (BASELINK_P (function)) qualified_p = true; @@ -22675,7 +22870,7 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) FUNCTION_DECL which is the desired context for access checking is not built yet. We solve this chicken-and-egg problem by deferring all checks until we have the FUNCTION_DECL. */ - push_deferring_access_checks (dk_deferred); + deferring_access_check_sentinel dacs (dk_deferred); /* Instantiation of the function happens in the context of the function template, not the context of the overload resolution we're doing. */ @@ -22733,10 +22928,13 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) pop_from_top_level (); if (fndecl == error_mark_node) - { - pop_deferring_access_checks (); - return error_mark_node; - } + return error_mark_node; + + /* Substituting the type might have recursively instantiated this + same alias (c++/117530). */ + if (DECL_ALIAS_TEMPLATE_P (gen_tmpl) + && (spec = retrieve_specialization (gen_tmpl, targ_ptr, hash))) + return spec; /* The DECL_TI_TEMPLATE should always be the immediate parent template, not the most general template. */ @@ -22771,7 +22969,6 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) access_ok = false; pop_access_scope (fndecl); } - pop_deferring_access_checks (); /* If we've just instantiated the main entry point for a function, instantiate all the alternate entry points as well. We do this @@ -23224,7 +23421,7 @@ fn_type_unification (tree fn, conversions that we know are not going to induce template instantiation (PR99599). */ if (strict == DEDUCE_CALL - && incomplete + && incomplete && flag_concepts && check_non_deducible_conversions (parms, args, nargs, fn, strict, flags, convs, explain_p, /*noninst_only_p=*/true)) @@ -23471,9 +23668,13 @@ maybe_adjust_types_for_deduction (tree tparms, return result; } -/* Return true if computing a conversion from FROM to TO might induce template - instantiation. Conversely, if this predicate returns false then computing - the conversion definitely won't induce template instantiation. */ +/* Return true if computing a conversion from FROM to TO might consider + user-defined conversions, which could lead to arbitrary template + instantiations (e.g. g++.dg/cpp2a/concepts-nondep1.C). If this predicate + returns false then computing the conversion definitely won't try UDCs. + + Note that this restriction parallels LOOKUP_DEFAULTED for CWG1092, but in + this case we want the early filter to pass instead of fail. */ static bool conversion_may_instantiate_p (tree to, tree from) @@ -23481,45 +23682,23 @@ conversion_may_instantiate_p (tree to, tree from) to = non_reference (to); from = non_reference (from); - bool ptr_conv_p = false; - if (TYPE_PTR_P (to) - && TYPE_PTR_P (from)) - { - to = TREE_TYPE (to); - from = TREE_TYPE (from); - ptr_conv_p = true; - } - - /* If one of the types is a not-yet-instantiated class template - specialization, then computing the conversion might instantiate - it in order to inspect bases, conversion functions and/or - converting constructors. */ - if ((CLASS_TYPE_P (to) - && !COMPLETE_TYPE_P (to) - && CLASSTYPE_TEMPLATE_INSTANTIATION (to)) - || (CLASS_TYPE_P (from) - && !COMPLETE_TYPE_P (from) - && CLASSTYPE_TEMPLATE_INSTANTIATION (from))) - return true; - - /* Converting from one pointer type to another, or between - reference-related types, always yields a standard conversion. */ - if (ptr_conv_p || reference_related_p (to, from)) + /* Converting between reference-related types is a standard conversion. */ + if (reference_related_p (to, from)) return false; /* Converting to a non-aggregate class type will consider its user-declared constructors, which might induce instantiation. */ - if (CLASS_TYPE_P (to) - && CLASSTYPE_NON_AGGREGATE (to)) + if (CLASS_TYPE_P (complete_type (to)) + && type_has_converting_constructor (to)) return true; /* Similarly, converting from a class type will consider its conversion functions. */ - if (CLASS_TYPE_P (from) + if (CLASS_TYPE_P (complete_type (from)) && TYPE_HAS_CONVERSION (from)) return true; - /* Otherwise, computing this conversion definitely won't induce + /* Otherwise, computing this conversion won't risk arbitrary template instantiation. */ return false; } @@ -24425,7 +24604,8 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain) } if (good == 1) { - mark_used (goodfn); + if (!mark_used (goodfn, complain) && !(complain & tf_error)) + return error_mark_node; expr = goodfn; if (baselink) expr = build_baselink (BASELINK_BINFO (baselink), @@ -25765,10 +25945,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)), INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (t)), UNIFY_ALLOW_NONE, explain_p); - else - return unify_success (explain_p); + gcc_checking_assert (t == arg); } - else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) + + if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) return unify_type_mismatch (explain_p, parm, arg); return unify_success (explain_p); @@ -27357,6 +27537,10 @@ tree template_for_substitution (tree decl) { tree tmpl = DECL_TI_TEMPLATE (decl); + if (VAR_P (decl)) + if (tree partial = most_specialized_partial_spec (decl, tf_none)) + if (partial != error_mark_node) + tmpl = TI_TEMPLATE (partial); /* Set TMPL to the template whose DECL_TEMPLATE_RESULT is the pattern for the instantiation. This is not always the most general @@ -27737,6 +27921,11 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p) if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) cp_check_omp_declare_reduction (d); + + if (int errs = errorcount + sorrycount) + if (errs > current_tinst_level->errors) + if (function *f = DECL_STRUCT_FUNCTION (d)) + f->language->erroneous = true; } /* We're not deferring instantiation any more. */ @@ -27930,7 +28119,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) || (external_p && VAR_P (d)) /* Handle here a deleted function too, avoid generating its body (c++/61080). */ - || deleted_p) + || deleted_p + /* We need the initializer for an OpenMP declare mapper. */ + || (VAR_P (d) && DECL_LANG_SPECIFIC (d) && DECL_OMP_DECLARE_MAPPER_P (d))) { /* The definition of the static data member is now required so we must substitute the initializer. */ @@ -28043,12 +28234,16 @@ instantiate_pending_templates (int retries) reconsider = 0; while (*t) { - tree instantiation = reopen_tinst_level ((*t)->tinst); - bool complete = false; + struct tinst_level *tinst = (*t)->tinst; + bool complete = tinst_complete_p (tinst); - if (TYPE_P (instantiation)) + if (!complete) { - if (!COMPLETE_TYPE_P (instantiation)) + tree instantiation = reopen_tinst_level (tinst); + + if (limit_bad_template_recursion (instantiation)) + /* Do nothing. */; + else if (TYPE_P (instantiation)) { instantiate_class_template (instantiation); if (CLASSTYPE_TEMPLATE_INSTANTIATION (instantiation)) @@ -28065,13 +28260,7 @@ instantiate_pending_templates (int retries) if (COMPLETE_TYPE_P (instantiation)) reconsider = 1; } - - complete = COMPLETE_TYPE_P (instantiation); - } - else - { - if (!DECL_TEMPLATE_SPECIALIZATION (instantiation) - && !DECL_TEMPLATE_INSTANTIATED (instantiation)) + else { instantiation = instantiate_decl (instantiation, @@ -28081,8 +28270,10 @@ instantiate_pending_templates (int retries) reconsider = 1; } - complete = (DECL_TEMPLATE_SPECIALIZATION (instantiation) - || DECL_TEMPLATE_INSTANTIATED (instantiation)); + complete = tinst_complete_p (tinst); + + tinst_depth = 0; + set_refcount_ptr (current_tinst_level); } if (complete) @@ -28099,8 +28290,6 @@ instantiate_pending_templates (int retries) last = *t; t = &(*t)->next; } - tinst_depth = 0; - set_refcount_ptr (current_tinst_level); } last_pending_template = last; } @@ -30923,9 +31112,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) tree aguides = NULL_TREE; tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms); unsigned natparms = TREE_VEC_LENGTH (atparms); - for (ovl_iterator iter (uguides); iter; ++iter) + for (tree f : lkp_range (uguides)) { - tree f = *iter; tree in_decl = f; location_t loc = DECL_SOURCE_LOCATION (f); tree ret = TREE_TYPE (TREE_TYPE (f)); diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc index 3539962..c06a18b 100644 --- a/gcc/cp/rtti.cc +++ b/gcc/cp/rtti.cc @@ -468,6 +468,7 @@ get_tinfo_decl_direct (tree type, tree name, int pseudo_ix) DECL_IGNORED_P (d) = 1; TREE_READONLY (d) = 1; TREE_STATIC (d) = 1; + TREE_ADDRESSABLE (d) = 1; /* Tell equal_address_to that different tinfo decls never overlap. */ if (vec_safe_is_empty (unemitted_tinfo_decls)) @@ -1318,18 +1319,9 @@ get_pseudo_ti_index (tree type) static tinfo_s * get_tinfo_desc (unsigned ix) { - unsigned len = tinfo_descs->length (); - - if (len <= ix) - { - /* too short, extend. */ - len = ix + 1 - len; - vec_safe_reserve (tinfo_descs, len); - tinfo_s elt; - elt.type = elt.vtable = elt.name = NULL_TREE; - while (len--) - tinfo_descs->quick_push (elt); - } + if (tinfo_descs->length () <= ix) + /* too short, extend. */ + vec_safe_grow_cleared (tinfo_descs, ix + 1); tinfo_s *res = &(*tinfo_descs)[ix]; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index a10ef34..28baf7b 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -45,13 +45,13 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "predict.h" #include "memmodel.h" +#include "gimplify.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or during template instantiation, which may be regarded as a degenerate form of parsing. */ -static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); /* Used for OpenMP non-static data member privatization. */ @@ -1116,7 +1116,7 @@ annotate_saver::restore (tree new_inner) statement. Convert it to a boolean value, if appropriate. In addition, verify sequence points if -Wsequence-point is enabled. */ -static tree +tree maybe_convert_cond (tree cond) { /* Empty conditions remain empty. */ @@ -1180,10 +1180,13 @@ finish_expr_stmt (tree expr) expr = error_mark_node; /* Simplification of inner statement expressions, compound exprs, - etc can result in us already having an EXPR_STMT. */ + etc can result in us already having an EXPR_STMT or other statement + tree. Don't wrap them in EXPR_STMT. */ if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) { - if (TREE_CODE (expr) != EXPR_STMT) + if (TREE_CODE (expr) != EXPR_STMT + && !STATEMENT_CLASS_P (expr) + && TREE_CODE (expr) != STATEMENT_LIST) expr = build_stmt (loc, EXPR_STMT, expr); expr = maybe_cleanup_point_expr_void (expr); } @@ -2767,7 +2770,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope, else if (PACK_EXPANSION_P (type)) /* Don't bother trying to represent this. */ type = NULL_TREE; - else if (WILDCARD_TYPE_P (TREE_TYPE (object))) + else if (!TREE_TYPE (object) || WILDCARD_TYPE_P (TREE_TYPE (object))) /* We don't know what the eventual quals will be, so punt until instantiation time. @@ -3082,6 +3085,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr) } else if (processing_template_decl) { + /* Not finish_expr_stmt because we don't want convert_to_void. */ expr = build_stmt (input_location, EXPR_STMT, expr); expr = add_stmt (expr); /* Mark the last statement so that we can recognize it as such at @@ -3321,6 +3325,14 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, if (type_dependent_expression_p (fn) || any_type_dependent_arguments_p (*args)) { + if (koenig_p + && TREE_CODE (orig_fn) == FUNCTION_DECL + && !fndecl_built_in_p (orig_fn)) + /* For an ADL-enabled call where unqualified lookup found a + single non-template function, wrap it in an OVERLOAD so that + later substitution doesn't overeagerly mark the function as + used. */ + orig_fn = ovl_make (orig_fn, NULL_TREE); result = build_min_nt_call_vec (orig_fn, *args); SET_EXPR_LOCATION (result, cp_expr_loc_or_input_loc (fn)); KOENIG_LOOKUP_P (result) = koenig_p; @@ -3593,16 +3605,11 @@ finish_this_expr (void) { tree result = NULL_TREE; - if (current_class_ptr) - { - tree type = TREE_TYPE (current_class_ref); - - /* In a lambda expression, 'this' refers to the captured 'this'. */ - if (LAMBDA_TYPE_P (type)) - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type), true); - else - result = current_class_ptr; - } + if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + result = (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type), /*add*/true)); + else if (current_class_ptr) + result = current_class_ptr; if (result) /* The keyword 'this' is a prvalue expression. */ @@ -5088,22 +5095,32 @@ static tree finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain) { idx = maybe_constant_value (idx, NULL_TREE, mce_true); - if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx))) + if (!INTEGRAL_TYPE_P (TREE_TYPE (idx))) + { + if (complain & tf_error) + error ("pack index has non-integral type %qT", TREE_TYPE (idx)); + return error_mark_node; + } + if (TREE_CODE (idx) != INTEGER_CST) { if (complain & tf_error) - error ("pack index is not an integral constant"); + { + error ("pack index is not an integral constant"); + cxx_constant_value (idx); + } return error_mark_node; } if (tree_int_cst_sgn (idx) < 0) { if (complain & tf_error) - error ("pack index is negative"); + error ("pack index %qE is negative", idx); return error_mark_node; } if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) { if (complain & tf_error) - error ("pack index is out of range"); + error ("pack index %qE is out of range for pack of length %qd", + idx, TREE_VEC_LENGTH (types)); return error_mark_node; } return TREE_VEC_ELT (types, tree_to_shwi (idx)); @@ -6723,6 +6740,97 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, return id; } +/* Return identifier to look up for omp declare mapper. */ + +tree +omp_mapper_id (tree mapper_id, tree type) +{ + const char *p = NULL; + const char *m = NULL; + + if (mapper_id == NULL_TREE) + p = ""; + else if (TREE_CODE (mapper_id) == IDENTIFIER_NODE) + p = IDENTIFIER_POINTER (mapper_id); + else + return error_mark_node; + + if (type != NULL_TREE) + m = mangle_type_string (TYPE_MAIN_VARIANT (type)); + + const char prefix[] = "omp declare mapper "; + size_t lenp = sizeof (prefix); + if (strncmp (p, prefix, lenp - 1) == 0) + lenp = 1; + size_t len = strlen (p); + size_t lenm = m ? strlen (m) + 1 : 0; + char *name = XALLOCAVEC (char, lenp + len + lenm); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + if (m) + { + name[lenp + len - 1] = '~'; + memcpy (name + lenp + len, m, lenm); + } + return get_identifier (name); +} + +tree +cxx_omp_mapper_lookup (tree id, tree type) +{ + if (!RECORD_OR_UNION_TYPE_P (type)) + return NULL_TREE; + id = omp_mapper_id (id, type); + return lookup_name (id); +} + +tree +cxx_omp_extract_mapper_directive (tree vardecl) +{ + gcc_assert (TREE_CODE (vardecl) == VAR_DECL); + + /* Instantiate the decl if we haven't already. */ + mark_used (vardecl); + tree body = DECL_INITIAL (vardecl); + + if (TREE_CODE (body) == STATEMENT_LIST) + { + tree_stmt_iterator tsi = tsi_start (body); + gcc_assert (TREE_CODE (tsi_stmt (tsi)) == DECL_EXPR); + tsi_next (&tsi); + body = tsi_stmt (tsi); + } + + gcc_assert (TREE_CODE (body) == OMP_DECLARE_MAPPER); + + return body; +} + +/* For now we can handle singleton OMP_ARRAY_SECTIONs with custom mappers, but + nothing more complicated. */ + +tree +cxx_omp_map_array_section (location_t loc, tree t) +{ + tree low = TREE_OPERAND (t, 1); + tree len = TREE_OPERAND (t, 2); + + if (len && integer_onep (len)) + { + t = TREE_OPERAND (t, 0); + + if (!low) + low = integer_zero_node; + + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + t = convert_from_reference (t); + + t = build_array_ref (loc, t, low); + } + + return t; +} + /* Helper function for cp_parser_omp_declare_reduction_exprs and tsubst_omp_udr. Remove CLEANUP_STMT for data (omp_priv variable). @@ -7204,6 +7312,33 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) return false; } +/* Check an instance of an "omp declare mapper" function. */ + +bool +cp_check_omp_declare_mapper (tree udm) +{ + tree type = TREE_TYPE (udm); + location_t loc = DECL_SOURCE_LOCATION (udm); + + if (type == error_mark_node) + return false; + + if (!processing_template_decl && !RECORD_OR_UNION_TYPE_P (type)) + { + error_at (loc, "%qT is not a struct, union or class type in " + "%<#pragma omp declare mapper%>", type); + return false; + } + if (!processing_template_decl && CLASSTYPE_VBASECLASSES (type)) + { + error_at (loc, "%qT must not be a virtual base class in " + "%<#pragma omp declare mapper%>", type); + return false; + } + + return true; +} + /* Called from finish_struct_1. linear(this) or linear(this:step) clauses might not be finalized yet because the class has been incomplete when parsing #pragma omp declare simd methods. Fix those up now. */ @@ -8848,6 +8983,12 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_MAP: if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved) goto move_implicit; + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME) + { + remove = true; + break; + } /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: @@ -10467,6 +10608,8 @@ struct omp_target_walk_data /* Local variables declared inside a BIND_EXPR, used to filter out such variables when recording lambda_objects_accessed. */ hash_set<tree> local_decls; + + omp_mapper_list<tree> *mappers; }; /* Helper function of finish_omp_target_clauses, called via @@ -10480,6 +10623,7 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr) struct omp_target_walk_data *data = (struct omp_target_walk_data *) ptr; tree current_object = data->current_object; tree current_closure = data->current_closure; + omp_mapper_list<tree> *mlist = data->mappers; /* References inside of these expression codes shouldn't incur any form of mapping, so return early. */ @@ -10493,6 +10637,27 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr) if (TREE_CODE (t) == OMP_CLAUSE) return NULL_TREE; + if (!processing_template_decl) + { + tree aggr_type = NULL_TREE; + + if (TREE_CODE (t) == COMPONENT_REF + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0)))) + aggr_type = TREE_TYPE (TREE_OPERAND (t, 0)); + else if ((TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))) + aggr_type = TREE_TYPE (t); + + if (aggr_type) + { + tree mapper_fn = cxx_omp_mapper_lookup (NULL_TREE, aggr_type); + if (mapper_fn) + mlist->add_mapper (NULL_TREE, aggr_type, mapper_fn); + } + } + if (current_object) { tree this_expr = TREE_OPERAND (current_object, 0); @@ -10543,10 +10708,10 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr) if (TREE_CODE (t) == BIND_EXPR) { - tree block = BIND_EXPR_BLOCK (t); - for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var)) - if (!data->local_decls.contains (var)) - data->local_decls.add (var); + if (tree block = BIND_EXPR_BLOCK (t)) + for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var)) + if (!data->local_decls.contains (var)) + data->local_decls.add (var); return NULL_TREE; } @@ -10595,10 +10760,48 @@ finish_omp_target_clauses (location_t loc, tree body, tree *clauses_ptr) else data.current_closure = NULL_TREE; - cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, &data); - auto_vec<tree, 16> new_clauses; + if (!processing_template_decl) + { + hash_set<omp_name_type<tree> > seen_types; + auto_vec<tree> mapper_fns; + omp_mapper_list<tree> mlist (&seen_types, &mapper_fns); + data.mappers = &mlist; + + cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, + &data); + + unsigned int i; + tree mapper_fn; + FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn) + c_omp_find_nested_mappers (&mlist, mapper_fn); + + FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn) + { + tree mapper = cxx_omp_extract_mapper_directive (mapper_fn); + if (mapper == error_mark_node) + continue; + tree mapper_name = OMP_DECLARE_MAPPER_ID (mapper); + tree decl = OMP_DECLARE_MAPPER_DECL (mapper); + if (BASELINK_P (mapper_fn)) + mapper_fn = BASELINK_FUNCTIONS (mapper_fn); + + tree c = build_omp_clause (loc, OMP_CLAUSE__MAPPER_BINDING_); + OMP_CLAUSE__MAPPER_BINDING__ID (c) = mapper_name; + OMP_CLAUSE__MAPPER_BINDING__DECL (c) = decl; + OMP_CLAUSE__MAPPER_BINDING__MAPPER (c) = mapper_fn; + + new_clauses.safe_push (c); + } + } + else + { + data.mappers = NULL; + cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, + &data); + } + tree omp_target_this_expr = NULL_TREE; tree *explicit_this_deref_map = NULL; if (data.this_expr_accessed) @@ -13213,6 +13416,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); + if (CLASS_TYPE_P (type1) && type_build_dtor_call (type1)) + { + deferring_access_check_sentinel dacs (dk_no_check); + cp_unevaluated un; + tree fn = get_dtor (type1, tf_none); + if (!fn && !seen_error ()) + warning (0, "checking %qs for type %qT with a destructor that " + "cannot be called", "__has_trivial_destructor", type1); + } return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); @@ -13268,6 +13480,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_CONVERTIBLE: return is_convertible (type1, type2); + case CPTK_IS_DESTRUCTIBLE: + return is_xible (BIT_NOT_EXPR, type1, NULL_TREE); + case CPTK_IS_EMPTY: return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1); @@ -13307,6 +13522,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_NOTHROW_CONVERTIBLE: return is_nothrow_convertible (type1, type2); + case CPTK_IS_NOTHROW_DESTRUCTIBLE: + return is_nothrow_xible (BIT_NOT_EXPR, type1, NULL_TREE); + case CPTK_IS_NOTHROW_INVOCABLE: return expr_noexcept_p (build_invoke (type1, type2, tf_none), tf_none); @@ -13349,6 +13567,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_TRIVIALLY_COPYABLE: return trivially_copyable_p (type1); + case CPTK_IS_TRIVIALLY_DESTRUCTIBLE: + return is_trivially_xible (BIT_NOT_EXPR, type1, NULL_TREE); + case CPTK_IS_UNBOUNDED_ARRAY: return array_of_unknown_bound_p (type1); @@ -13372,8 +13593,10 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_DEDUCIBLE: return type_targs_deducible_from (type1, type2); - /* __array_rank is handled in finish_trait_expr. */ + /* __array_rank and __builtin_type_order are handled in + finish_trait_expr. */ case CPTK_RANK: + case CPTK_TYPE_ORDER: gcc_unreachable (); #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ @@ -13503,6 +13726,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) tree trait_expr = make_node (TRAIT_EXPR); if (kind == CPTK_RANK) TREE_TYPE (trait_expr) = size_type_node; + else if (kind == CPTK_TYPE_ORDER) + { + tree val = type_order_value (type1, type1); + if (val != error_mark_node) + TREE_TYPE (trait_expr) = TREE_TYPE (val); + } else TREE_TYPE (trait_expr) = boolean_type_node; TRAIT_EXPR_TYPE1 (trait_expr) = type1; @@ -13521,6 +13750,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_NOTHROW_COPY: case CPTK_HAS_TRIVIAL_COPY: case CPTK_HAS_TRIVIAL_DESTRUCTOR: + case CPTK_IS_DESTRUCTIBLE: + case CPTK_IS_NOTHROW_DESTRUCTIBLE: + case CPTK_IS_TRIVIALLY_DESTRUCTIBLE: if (!check_trait_type (type1)) return error_mark_node; break; @@ -13607,6 +13839,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_UNION: case CPTK_IS_VOLATILE: case CPTK_RANK: + case CPTK_TYPE_ORDER: break; case CPTK_IS_LAYOUT_COMPATIBLE: @@ -13646,6 +13879,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) ++rank; val = build_int_cst (size_type_node, rank); } + else if (kind == CPTK_TYPE_ORDER) + val = type_order_value (type1, type2); else val = (trait_expr_value (kind, type1, type2) ? boolean_true_node : boolean_false_node); diff --git a/gcc/cp/std-name-hint.h b/gcc/cp/std-name-hint.h index dde2f9b..c5f8004 100644 --- a/gcc/cp/std-name-hint.h +++ b/gcc/cp/std-name-hint.h @@ -144,979 +144,979 @@ std_name_hint_lookup::find (const char *str, size_t len) static const struct std_name_hint wordlist[] = { -#line 130 "../../src/gcc/cp/std-name-hint.gperf" +#line 130 "std-name-hint.gperf" {"regular", "<concepts>", cxx20}, -#line 292 "../../src/gcc/cp/std-name-hint.gperf" +#line 292 "std-name-hint.gperf" {"reverse_iterator", "<iterator>", cxx98}, -#line 454 "../../src/gcc/cp/std-name-hint.gperf" +#line 454 "std-name-hint.gperf" {"range_error", "<stdexcept>", cxx98}, -#line 408 "../../src/gcc/cp/std-name-hint.gperf" +#line 408 "std-name-hint.gperf" {"set", "<set>", cxx98}, -#line 231 "../../src/gcc/cp/std-name-hint.gperf" +#line 231 "std-name-hint.gperf" {"setbase", "<iomanip>", cxx98}, -#line 325 "../../src/gcc/cp/std-name-hint.gperf" +#line 325 "std-name-hint.gperf" {"reinterpret_pointer_cast", "<memory>", cxx17}, -#line 288 "../../src/gcc/cp/std-name-hint.gperf" +#line 288 "std-name-hint.gperf" {"next", "<iterator>", cxx11}, -#line 171 "../../src/gcc/cp/std-name-hint.gperf" +#line 171 "std-name-hint.gperf" {"format", "<format>", cxx20}, -#line 181 "../../src/gcc/cp/std-name-hint.gperf" +#line 181 "std-name-hint.gperf" {"formatter", "<format>", cxx20}, -#line 196 "../../src/gcc/cp/std-name-hint.gperf" +#line 196 "std-name-hint.gperf" {"basic_filebuf", "<fstream>", cxx98}, -#line 575 "../../src/gcc/cp/std-name-hint.gperf" +#line 575 "std-name-hint.gperf" {"pair", "<utility>", cxx98}, -#line 276 "../../src/gcc/cp/std-name-hint.gperf" +#line 276 "std-name-hint.gperf" {"begin", "<iterator>", cxx11}, -#line 179 "../../src/gcc/cp/std-name-hint.gperf" +#line 179 "std-name-hint.gperf" {"formattable", "<format>", cxx23}, -#line 541 "../../src/gcc/cp/std-name-hint.gperf" +#line 541 "std-name-hint.gperf" {"bad_cast", "<typeinfo>", cxx98}, -#line 233 "../../src/gcc/cp/std-name-hint.gperf" +#line 233 "std-name-hint.gperf" {"setiosflags", "<iomanip>", cxx98}, -#line 393 "../../src/gcc/cp/std-name-hint.gperf" +#line 393 "std-name-hint.gperf" {"print", "<print>", cxx23}, -#line 221 "../../src/gcc/cp/std-name-hint.gperf" +#line 221 "std-name-hint.gperf" {"promise", "<future>", cxx11}, -#line 581 "../../src/gcc/cp/std-name-hint.gperf" +#line 581 "std-name-hint.gperf" {"bad_variant_access", "<variant>", cxx17}, -#line 328 "../../src/gcc/cp/std-name-hint.gperf" +#line 328 "std-name-hint.gperf" {"to_address", "<memory>", cxx20}, -#line 420 "../../src/gcc/cp/std-name-hint.gperf" +#line 420 "std-name-hint.gperf" {"basic_spanbuf", "<spanstream>", cxx23}, -#line 106 "../../src/gcc/cp/std-name-hint.gperf" +#line 106 "std-name-hint.gperf" {"same_as", "<concepts>", cxx20}, -#line 336 "../../src/gcc/cp/std-name-hint.gperf" +#line 336 "std-name-hint.gperf" {"pmr", "<memory_resource>", cxx17}, -#line 180 "../../src/gcc/cp/std-name-hint.gperf" +#line 180 "std-name-hint.gperf" {"formatted_size", "<format>", cxx20}, -#line 275 "../../src/gcc/cp/std-name-hint.gperf" +#line 275 "std-name-hint.gperf" {"back_inserter", "<iterator>", cxx98}, -#line 251 "../../src/gcc/cp/std-name-hint.gperf" +#line 251 "std-name-hint.gperf" {"nouppercase", "<ios>", cxx98}, -#line 250 "../../src/gcc/cp/std-name-hint.gperf" +#line 250 "std-name-hint.gperf" {"nounitbuf", "<ios>", cxx98}, -#line 433 "../../src/gcc/cp/std-name-hint.gperf" +#line 433 "std-name-hint.gperf" {"basic_stringbuf", "<sstream>", cxx98}, -#line 592 "../../src/gcc/cp/std-name-hint.gperf" +#line 592 "std-name-hint.gperf" {"vector", "<vector>", cxx98}, -#line 246 "../../src/gcc/cp/std-name-hint.gperf" +#line 246 "std-name-hint.gperf" {"noshowbase", "<ios>", cxx98}, -#line 219 "../../src/gcc/cp/std-name-hint.gperf" +#line 219 "std-name-hint.gperf" {"future", "<future>", cxx11}, -#line 340 "../../src/gcc/cp/std-name-hint.gperf" +#line 340 "std-name-hint.gperf" {"pmr::new_delete_resource", "<memory_resource>", cxx17}, -#line 337 "../../src/gcc/cp/std-name-hint.gperf" +#line 337 "std-name-hint.gperf" {"pmr::get_default_resource", "<memory_resource>", cxx17}, -#line 343 "../../src/gcc/cp/std-name-hint.gperf" +#line 343 "std-name-hint.gperf" {"pmr::set_default_resource", "<memory_resource>", cxx17}, -#line 455 "../../src/gcc/cp/std-name-hint.gperf" +#line 455 "std-name-hint.gperf" {"runtime_error", "<stdexcept>", cxx98}, -#line 516 "../../src/gcc/cp/std-name-hint.gperf" +#line 516 "std-name-hint.gperf" {"tuple", "<tuple>", cxx11}, -#line 132 "../../src/gcc/cp/std-name-hint.gperf" +#line 132 "std-name-hint.gperf" {"regular_invocable", "<concepts>", cxx20}, -#line 116 "../../src/gcc/cp/std-name-hint.gperf" +#line 116 "std-name-hint.gperf" {"swappable", "<concepts>", cxx20}, -#line 186 "../../src/gcc/cp/std-name-hint.gperf" +#line 186 "std-name-hint.gperf" {"runtime_format", "<format>", cxx26}, -#line 211 "../../src/gcc/cp/std-name-hint.gperf" +#line 211 "std-name-hint.gperf" {"not_fn", "<functional>", cxx17}, -#line 142 "../../src/gcc/cp/std-name-hint.gperf" +#line 142 "std-name-hint.gperf" {"byte", "<cstddef>", cxx17}, -#line 518 "../../src/gcc/cp/std-name-hint.gperf" +#line 518 "std-name-hint.gperf" {"tuple_element", "<tuple>", cxx11}, -#line 519 "../../src/gcc/cp/std-name-hint.gperf" +#line 519 "std-name-hint.gperf" {"tuple_element_t", "<tuple>", cxx14}, -#line 584 "../../src/gcc/cp/std-name-hint.gperf" +#line 584 "std-name-hint.gperf" {"variant", "<variant>", cxx17}, -#line 386 "../../src/gcc/cp/std-name-hint.gperf" +#line 386 "std-name-hint.gperf" {"ends", "<ostream>", cxx98}, -#line 520 "../../src/gcc/cp/std-name-hint.gperf" +#line 520 "std-name-hint.gperf" {"tuple_size", "<tuple>", cxx11}, -#line 123 "../../src/gcc/cp/std-name-hint.gperf" +#line 123 "std-name-hint.gperf" {"equality_comparable", "<concepts>", cxx20}, -#line 247 "../../src/gcc/cp/std-name-hint.gperf" +#line 247 "std-name-hint.gperf" {"noshowpoint", "<ios>", cxx98}, -#line 394 "../../src/gcc/cp/std-name-hint.gperf" +#line 394 "std-name-hint.gperf" {"println", "<print>", cxx23}, -#line 248 "../../src/gcc/cp/std-name-hint.gperf" +#line 248 "std-name-hint.gperf" {"noshowpos", "<ios>", cxx98}, -#line 388 "../../src/gcc/cp/std-name-hint.gperf" +#line 388 "std-name-hint.gperf" {"flush_emit", "<ostream>", cxx20}, -#line 585 "../../src/gcc/cp/std-name-hint.gperf" +#line 585 "std-name-hint.gperf" {"variant_alternative", "<variant>", cxx17}, -#line 537 "../../src/gcc/cp/std-name-hint.gperf" +#line 537 "std-name-hint.gperf" {"void_t", "<type_traits>", cxx17}, -#line 586 "../../src/gcc/cp/std-name-hint.gperf" +#line 586 "std-name-hint.gperf" {"variant_alternative_t", "<variant>", cxx17}, -#line 134 "../../src/gcc/cp/std-name-hint.gperf" +#line 134 "std-name-hint.gperf" {"relation", "<concepts>", cxx20}, -#line 461 "../../src/gcc/cp/std-name-hint.gperf" +#line 461 "std-name-hint.gperf" {"float32_t", "<stdfloat>", cxx23}, -#line 459 "../../src/gcc/cp/std-name-hint.gperf" +#line 459 "std-name-hint.gperf" {"float128_t", "<stdfloat>", cxx23}, -#line 381 "../../src/gcc/cp/std-name-hint.gperf" +#line 381 "std-name-hint.gperf" {"nullopt", "<optional>", cxx17}, -#line 291 "../../src/gcc/cp/std-name-hint.gperf" +#line 291 "std-name-hint.gperf" {"prev", "<iterator>", cxx11}, -#line 425 "../../src/gcc/cp/std-name-hint.gperf" +#line 425 "std-name-hint.gperf" {"spanbuf", "<spanstream>", cxx23}, -#line 513 "../../src/gcc/cp/std-name-hint.gperf" +#line 513 "std-name-hint.gperf" {"make_from_tuple", "<tuple>", cxx17}, -#line 253 "../../src/gcc/cp/std-name-hint.gperf" +#line 253 "std-name-hint.gperf" {"right", "<ios>", cxx98}, -#line 210 "../../src/gcc/cp/std-name-hint.gperf" +#line 210 "std-name-hint.gperf" {"mem_fn", "<functional>", cxx11}, -#line 515 "../../src/gcc/cp/std-name-hint.gperf" +#line 515 "std-name-hint.gperf" {"tie", "<tuple>", cxx11}, -#line 197 "../../src/gcc/cp/std-name-hint.gperf" +#line 197 "std-name-hint.gperf" {"basic_fstream", "<fstream>", cxx98}, -#line 573 "../../src/gcc/cp/std-name-hint.gperf" +#line 573 "std-name-hint.gperf" {"move", "<utility>", cxx11}, -#line 462 "../../src/gcc/cp/std-name-hint.gperf" +#line 462 "std-name-hint.gperf" {"float64_t", "<stdfloat>", cxx23}, -#line 127 "../../src/gcc/cp/std-name-hint.gperf" +#line 127 "std-name-hint.gperf" {"movable", "<concepts>", cxx20}, -#line 282 "../../src/gcc/cp/std-name-hint.gperf" +#line 282 "std-name-hint.gperf" {"front_inserter", "<iterator>", cxx98}, -#line 296 "../../src/gcc/cp/std-name-hint.gperf" +#line 296 "std-name-hint.gperf" {"map", "<map>", cxx98}, -#line 460 "../../src/gcc/cp/std-name-hint.gperf" +#line 460 "std-name-hint.gperf" {"float16_t", "<stdfloat>", cxx23}, -#line 56 "../../src/gcc/cp/std-name-hint.gperf" +#line 56 "std-name-hint.gperf" {"bitset", "<bitset>", cxx11}, -#line 205 "../../src/gcc/cp/std-name-hint.gperf" +#line 205 "std-name-hint.gperf" {"bind_front", "<functional>", cxx20}, -#line 574 "../../src/gcc/cp/std-name-hint.gperf" +#line 574 "std-name-hint.gperf" {"move_if_noexcept", "<utility>", cxx11}, -#line 274 "../../src/gcc/cp/std-name-hint.gperf" +#line 274 "std-name-hint.gperf" {"advance", "<iterator>", cxx98}, -#line 287 "../../src/gcc/cp/std-name-hint.gperf" +#line 287 "std-name-hint.gperf" {"move_iterator", "<iterator>", cxx11}, -#line 161 "../../src/gcc/cp/std-name-hint.gperf" +#line 161 "std-name-hint.gperf" {"terminate", "<exception>", cxx98}, -#line 531 "../../src/gcc/cp/std-name-hint.gperf" +#line 531 "std-name-hint.gperf" {"negation", "<type_traits>", cxx17}, -#line 318 "../../src/gcc/cp/std-name-hint.gperf" +#line 318 "std-name-hint.gperf" {"make_obj_using_allocator", "<memory>", cxx20}, -#line 321 "../../src/gcc/cp/std-name-hint.gperf" +#line 321 "std-name-hint.gperf" {"make_unique", "<memory>", cxx14}, -#line 255 "../../src/gcc/cp/std-name-hint.gperf" +#line 255 "std-name-hint.gperf" {"showbase", "<ios>", cxx98}, -#line 416 "../../src/gcc/cp/std-name-hint.gperf" +#line 416 "std-name-hint.gperf" {"span", "<span>", cxx20}, -#line 185 "../../src/gcc/cp/std-name-hint.gperf" +#line 185 "std-name-hint.gperf" {"range_formatter", "<format>", cxx23}, -#line 299 "../../src/gcc/cp/std-name-hint.gperf" +#line 299 "std-name-hint.gperf" {"addressof", "<memory>", cxx11}, -#line 571 "../../src/gcc/cp/std-name-hint.gperf" +#line 571 "std-name-hint.gperf" {"make_integer_sequence", "<utility>", cxx14}, -#line 184 "../../src/gcc/cp/std-name-hint.gperf" +#line 184 "std-name-hint.gperf" {"range_format", "<format>", cxx23}, -#line 322 "../../src/gcc/cp/std-name-hint.gperf" +#line 322 "std-name-hint.gperf" {"make_unique_for_overwrite", "<memory>", cxx20}, -#line 421 "../../src/gcc/cp/std-name-hint.gperf" +#line 421 "std-name-hint.gperf" {"basic_spanstream", "<spanstream>", cxx23}, -#line 257 "../../src/gcc/cp/std-name-hint.gperf" +#line 257 "std-name-hint.gperf" {"showpos", "<ios>", cxx98}, -#line 550 "../../src/gcc/cp/std-name-hint.gperf" +#line 550 "std-name-hint.gperf" {"as_const", "<utility>", cxx17}, -#line 308 "../../src/gcc/cp/std-name-hint.gperf" +#line 308 "std-name-hint.gperf" {"bad_weak_ptr", "<memory>", cxx11}, -#line 168 "../../src/gcc/cp/std-name-hint.gperf" +#line 168 "std-name-hint.gperf" {"basic_format_context", "<format>", cxx20}, -#line 434 "../../src/gcc/cp/std-name-hint.gperf" +#line 434 "std-name-hint.gperf" {"basic_stringstream", "<sstream>", cxx98}, -#line 539 "../../src/gcc/cp/std-name-hint.gperf" +#line 539 "std-name-hint.gperf" {"type_index", "<typeindex>", cxx11}, -#line 169 "../../src/gcc/cp/std-name-hint.gperf" +#line 169 "std-name-hint.gperf" {"basic_format_parse_context", "<format>", cxx20}, -#line 160 "../../src/gcc/cp/std-name-hint.gperf" +#line 160 "std-name-hint.gperf" {"make_exception_ptr", "<exception>", cxx11}, -#line 468 "../../src/gcc/cp/std-name-hint.gperf" +#line 468 "std-name-hint.gperf" {"basic_streambuf", "<streambuf>", cxx98}, -#line 167 "../../src/gcc/cp/std-name-hint.gperf" +#line 167 "std-name-hint.gperf" {"basic_format_args", "<format>", cxx20}, -#line 588 "../../src/gcc/cp/std-name-hint.gperf" +#line 588 "std-name-hint.gperf" {"variant_size", "<variant>", cxx17}, -#line 407 "../../src/gcc/cp/std-name-hint.gperf" +#line 407 "std-name-hint.gperf" {"multiset", "<set>", cxx98}, -#line 133 "../../src/gcc/cp/std-name-hint.gperf" +#line 133 "std-name-hint.gperf" {"predicate", "<concepts>", cxx20}, -#line 397 "../../src/gcc/cp/std-name-hint.gperf" +#line 397 "std-name-hint.gperf" {"queue", "<queue>", cxx98}, -#line 353 "../../src/gcc/cp/std-name-hint.gperf" +#line 353 "std-name-hint.gperf" {"recursive_timed_mutex", "<mutex>", cxx11}, -#line 399 "../../src/gcc/cp/std-name-hint.gperf" +#line 399 "std-name-hint.gperf" {"ranges::enable_borrowed_range", "<ranges>", cxx20}, -#line 533 "../../src/gcc/cp/std-name-hint.gperf" +#line 533 "std-name-hint.gperf" {"remove_cvref", "<type_traits>", cxx20}, -#line 206 "../../src/gcc/cp/std-name-hint.gperf" +#line 206 "std-name-hint.gperf" {"function", "<functional>", cxx11}, -#line 532 "../../src/gcc/cp/std-name-hint.gperf" +#line 532 "std-name-hint.gperf" {"negation_v", "<type_traits>", cxx17}, -#line 534 "../../src/gcc/cp/std-name-hint.gperf" +#line 534 "std-name-hint.gperf" {"remove_cvref_t", "<type_traits>", cxx20}, -#line 289 "../../src/gcc/cp/std-name-hint.gperf" +#line 289 "std-name-hint.gperf" {"ostream_iterator", "<iterator>", cxx98}, -#line 587 "../../src/gcc/cp/std-name-hint.gperf" +#line 587 "std-name-hint.gperf" {"variant_npos", "<variant>", cxx17}, -#line 244 "../../src/gcc/cp/std-name-hint.gperf" +#line 244 "std-name-hint.gperf" {"left", "<ios>", cxx98}, -#line 200 "../../src/gcc/cp/std-name-hint.gperf" +#line 200 "std-name-hint.gperf" {"fstream", "<fstream>", cxx98}, -#line 590 "../../src/gcc/cp/std-name-hint.gperf" +#line 590 "std-name-hint.gperf" {"visit", "<variant>", cxx17}, -#line 208 "../../src/gcc/cp/std-name-hint.gperf" +#line 208 "std-name-hint.gperf" {"invoke", "<functional>", cxx17}, -#line 137 "../../src/gcc/cp/std-name-hint.gperf" +#line 137 "std-name-hint.gperf" {"ranges::swap", "<concepts>", cxx20}, -#line 283 "../../src/gcc/cp/std-name-hint.gperf" +#line 283 "std-name-hint.gperf" {"inserter", "<iterator>", cxx98}, -#line 362 "../../src/gcc/cp/std-name-hint.gperf" +#line 362 "std-name-hint.gperf" {"launder", "<new>", cxx17}, -#line 228 "../../src/gcc/cp/std-name-hint.gperf" +#line 228 "std-name-hint.gperf" {"put_time", "<iomanip>", cxx11}, -#line 237 "../../src/gcc/cp/std-name-hint.gperf" +#line 237 "std-name-hint.gperf" {"boolalpha", "<ios>", cxx98}, -#line 361 "../../src/gcc/cp/std-name-hint.gperf" +#line 361 "std-name-hint.gperf" {"hardware_destructive_interference_size", "<new>", cxx17}, -#line 199 "../../src/gcc/cp/std-name-hint.gperf" +#line 199 "std-name-hint.gperf" {"basic_ofstream", "<fstream>", cxx98}, -#line 324 "../../src/gcc/cp/std-name-hint.gperf" +#line 324 "std-name-hint.gperf" {"pointer_traits", "<memory>", cxx11}, -#line 131 "../../src/gcc/cp/std-name-hint.gperf" +#line 131 "std-name-hint.gperf" {"invocable", "<concepts>", cxx20}, -#line 426 "../../src/gcc/cp/std-name-hint.gperf" +#line 426 "std-name-hint.gperf" {"spanstream", "<spanstream>", cxx23}, -#line 182 "../../src/gcc/cp/std-name-hint.gperf" +#line 182 "std-name-hint.gperf" {"make_format_args", "<format>", cxx20}, -#line 121 "../../src/gcc/cp/std-name-hint.gperf" +#line 121 "std-name-hint.gperf" {"move_constructible", "<concepts>", cxx20}, -#line 114 "../../src/gcc/cp/std-name-hint.gperf" +#line 114 "std-name-hint.gperf" {"floating_point", "<concepts>", cxx20}, -#line 258 "../../src/gcc/cp/std-name-hint.gperf" +#line 258 "std-name-hint.gperf" {"skipws", "<ios>", cxx98}, -#line 241 "../../src/gcc/cp/std-name-hint.gperf" +#line 241 "std-name-hint.gperf" {"hex", "<ios>", cxx98}, -#line 568 "../../src/gcc/cp/std-name-hint.gperf" +#line 568 "std-name-hint.gperf" {"index_sequence_for", "<utility>", cxx14}, -#line 567 "../../src/gcc/cp/std-name-hint.gperf" +#line 567 "std-name-hint.gperf" {"index_sequence", "<utility>", cxx14}, -#line 350 "../../src/gcc/cp/std-name-hint.gperf" +#line 350 "std-name-hint.gperf" {"mutex", "<mutex>", cxx11}, -#line 284 "../../src/gcc/cp/std-name-hint.gperf" +#line 284 "std-name-hint.gperf" {"istream_iterator", "<iterator>", cxx98}, -#line 334 "../../src/gcc/cp/std-name-hint.gperf" +#line 334 "std-name-hint.gperf" {"weak_ptr", "<memory>", cxx11}, -#line 173 "../../src/gcc/cp/std-name-hint.gperf" +#line 173 "std-name-hint.gperf" {"format_context", "<format>", cxx20}, -#line 451 "../../src/gcc/cp/std-name-hint.gperf" +#line 451 "std-name-hint.gperf" {"logic_error", "<stdexcept>", cxx98}, -#line 372 "../../src/gcc/cp/std-name-hint.gperf" +#line 372 "std-name-hint.gperf" {"numbers::ln2_v", "<numbers>", cxx20}, -#line 371 "../../src/gcc/cp/std-name-hint.gperf" +#line 371 "std-name-hint.gperf" {"numbers::ln10_v", "<numbers>", cxx20}, -#line 368 "../../src/gcc/cp/std-name-hint.gperf" +#line 368 "std-name-hint.gperf" {"numbers::inv_pi_v", "<numbers>", cxx20}, -#line 235 "../../src/gcc/cp/std-name-hint.gperf" +#line 235 "std-name-hint.gperf" {"setw", "<iomanip>", cxx98}, -#line 369 "../../src/gcc/cp/std-name-hint.gperf" +#line 369 "std-name-hint.gperf" {"numbers::inv_sqrt3_v", "<numbers>", cxx20}, -#line 370 "../../src/gcc/cp/std-name-hint.gperf" +#line 370 "std-name-hint.gperf" {"numbers::inv_sqrtpi_v", "<numbers>", cxx20}, -#line 230 "../../src/gcc/cp/std-name-hint.gperf" +#line 230 "std-name-hint.gperf" {"resetiosflags", "<iomanip>", cxx98}, -#line 303 "../../src/gcc/cp/std-name-hint.gperf" +#line 303 "std-name-hint.gperf" {"allocator", "<memory>", cxx98}, -#line 135 "../../src/gcc/cp/std-name-hint.gperf" +#line 135 "std-name-hint.gperf" {"equivalence_relation", "<concepts>", cxx20}, -#line 272 "../../src/gcc/cp/std-name-hint.gperf" +#line 272 "std-name-hint.gperf" {"ws", "<istream>", cxx98}, -#line 44 "../../src/gcc/cp/std-name-hint.gperf" +#line 44 "std-name-hint.gperf" {"any_cast", "<any>", cxx17}, -#line 198 "../../src/gcc/cp/std-name-hint.gperf" +#line 198 "std-name-hint.gperf" {"basic_ifstream", "<fstream>", cxx98}, -#line 175 "../../src/gcc/cp/std-name-hint.gperf" +#line 175 "std-name-hint.gperf" {"format_parse_context", "<format>", cxx20}, -#line 341 "../../src/gcc/cp/std-name-hint.gperf" +#line 341 "std-name-hint.gperf" {"pmr::polymorphic_allocator", "<memory_resource>", cxx17}, -#line 419 "../../src/gcc/cp/std-name-hint.gperf" +#line 419 "std-name-hint.gperf" {"basic_ospanstream", "<spanstream>", cxx23}, -#line 572 "../../src/gcc/cp/std-name-hint.gperf" +#line 572 "std-name-hint.gperf" {"make_pair", "<utility>", cxx98}, -#line 172 "../../src/gcc/cp/std-name-hint.gperf" +#line 172 "std-name-hint.gperf" {"format_args", "<format>", cxx20}, -#line 475 "../../src/gcc/cp/std-name-hint.gperf" +#line 475 "std-name-hint.gperf" {"stof", "<string>", cxx11}, -#line 339 "../../src/gcc/cp/std-name-hint.gperf" +#line 339 "std-name-hint.gperf" {"pmr::monotonic_buffer_resource", "<memory_resource>", cxx17}, -#line 342 "../../src/gcc/cp/std-name-hint.gperf" +#line 342 "std-name-hint.gperf" {"pmr::pool_options", "<memory_resource>", cxx17}, -#line 256 "../../src/gcc/cp/std-name-hint.gperf" +#line 256 "std-name-hint.gperf" {"showpoint", "<ios>", cxx98}, -#line 446 "../../src/gcc/cp/std-name-hint.gperf" +#line 446 "std-name-hint.gperf" {"stacktrace", "<stacktrace>", cxx23}, -#line 589 "../../src/gcc/cp/std-name-hint.gperf" +#line 589 "std-name-hint.gperf" {"variant_size_v", "<variant>", cxx17}, -#line 212 "../../src/gcc/cp/std-name-hint.gperf" +#line 212 "std-name-hint.gperf" {"reference_wrapper", "<functional>", cxx11}, -#line 262 "../../src/gcc/cp/std-name-hint.gperf" +#line 262 "std-name-hint.gperf" {"cerr", "<iostream>", cxx98}, -#line 300 "../../src/gcc/cp/std-name-hint.gperf" +#line 300 "std-name-hint.gperf" {"align", "<memory>", cxx11}, -#line 438 "../../src/gcc/cp/std-name-hint.gperf" +#line 438 "std-name-hint.gperf" {"stringbuf", "<sstream>", cxx98}, -#line 469 "../../src/gcc/cp/std-name-hint.gperf" +#line 469 "std-name-hint.gperf" {"streambuf", "<streambuf>", cxx98}, -#line 306 "../../src/gcc/cp/std-name-hint.gperf" +#line 306 "std-name-hint.gperf" {"allocator_traits", "<memory>", cxx11}, -#line 183 "../../src/gcc/cp/std-name-hint.gperf" +#line 183 "std-name-hint.gperf" {"make_wformat_args", "<format>", cxx20}, -#line 583 "../../src/gcc/cp/std-name-hint.gperf" +#line 583 "std-name-hint.gperf" {"monostate", "<variant>", cxx17}, -#line 387 "../../src/gcc/cp/std-name-hint.gperf" +#line 387 "std-name-hint.gperf" {"flush", "<ostream>", cxx98}, -#line 527 "../../src/gcc/cp/std-name-hint.gperf" +#line 527 "std-name-hint.gperf" {"enable_if", "<type_traits>", cxx11}, -#line 352 "../../src/gcc/cp/std-name-hint.gperf" +#line 352 "std-name-hint.gperf" {"recursive_mutex", "<mutex>", cxx11}, -#line 418 "../../src/gcc/cp/std-name-hint.gperf" +#line 418 "std-name-hint.gperf" {"basic_ispanstream", "<spanstream>", cxx23}, -#line 178 "../../src/gcc/cp/std-name-hint.gperf" +#line 178 "std-name-hint.gperf" {"format_to_n", "<format>", cxx20}, -#line 338 "../../src/gcc/cp/std-name-hint.gperf" +#line 338 "std-name-hint.gperf" {"pmr::memory_resource", "<memory_resource>", cxx17}, -#line 124 "../../src/gcc/cp/std-name-hint.gperf" +#line 124 "std-name-hint.gperf" {"equality_comparable_with", "<concepts>", cxx20}, -#line 493 "../../src/gcc/cp/std-name-hint.gperf" +#line 493 "std-name-hint.gperf" {"errc", "<system_error>", cxx11}, -#line 344 "../../src/gcc/cp/std-name-hint.gperf" +#line 344 "std-name-hint.gperf" {"pmr::synchronized_pool_resource", "<memory_resource>", cxx17}, -#line 385 "../../src/gcc/cp/std-name-hint.gperf" +#line 385 "std-name-hint.gperf" {"endl", "<ostream>", cxx98}, -#line 495 "../../src/gcc/cp/std-name-hint.gperf" +#line 495 "std-name-hint.gperf" {"error_code", "<system_error>", cxx11}, -#line 528 "../../src/gcc/cp/std-name-hint.gperf" +#line 528 "std-name-hint.gperf" {"enable_if_t", "<type_traits>", cxx14}, -#line 390 "../../src/gcc/cp/std-name-hint.gperf" +#line 390 "std-name-hint.gperf" {"ostream", "<ostream>", cxx98}, -#line 374 "../../src/gcc/cp/std-name-hint.gperf" +#line 374 "std-name-hint.gperf" {"numbers::log2e_v", "<numbers>", cxx20}, -#line 373 "../../src/gcc/cp/std-name-hint.gperf" +#line 373 "std-name-hint.gperf" {"numbers::log10e_v", "<numbers>", cxx20}, -#line 364 "../../src/gcc/cp/std-name-hint.gperf" +#line 364 "std-name-hint.gperf" {"nothrow_t", "<new>", cxx98}, -#line 512 "../../src/gcc/cp/std-name-hint.gperf" +#line 512 "std-name-hint.gperf" {"ignore", "<tuple>", cxx11}, -#line 360 "../../src/gcc/cp/std-name-hint.gperf" +#line 360 "std-name-hint.gperf" {"hardware_constructive_interference_size", "<new>", cxx17}, -#line 396 "../../src/gcc/cp/std-name-hint.gperf" +#line 396 "std-name-hint.gperf" {"priority_queue", "<queue>", cxx98}, -#line 424 "../../src/gcc/cp/std-name-hint.gperf" +#line 424 "std-name-hint.gperf" {"ospanstream", "<spanstream>", cxx23}, -#line 316 "../../src/gcc/cp/std-name-hint.gperf" +#line 316 "std-name-hint.gperf" {"enable_shared_from_this", "<memory>", cxx11}, -#line 265 "../../src/gcc/cp/std-name-hint.gperf" +#line 265 "std-name-hint.gperf" {"cout", "<iostream>", cxx98}, -#line 552 "../../src/gcc/cp/std-name-hint.gperf" +#line 552 "std-name-hint.gperf" {"cmp_greater", "<utility>", cxx20}, -#line 490 "../../src/gcc/cp/std-name-hint.gperf" +#line 490 "std-name-hint.gperf" {"basic_string_view", "<string_view>", cxx17}, -#line 249 "../../src/gcc/cp/std-name-hint.gperf" +#line 249 "std-name-hint.gperf" {"noskipws", "<ios>", cxx98}, -#line 177 "../../src/gcc/cp/std-name-hint.gperf" +#line 177 "std-name-hint.gperf" {"format_to", "<format>", cxx20}, -#line 502 "../../src/gcc/cp/std-name-hint.gperf" +#line 502 "std-name-hint.gperf" {"make_error_code", "<system_error>", cxx11}, -#line 174 "../../src/gcc/cp/std-name-hint.gperf" +#line 174 "std-name-hint.gperf" {"format_error", "<format>", cxx20}, -#line 347 "../../src/gcc/cp/std-name-hint.gperf" +#line 347 "std-name-hint.gperf" {"call_once", "<mutex>", cxx11}, -#line 377 "../../src/gcc/cp/std-name-hint.gperf" +#line 377 "std-name-hint.gperf" {"numbers::sqrt2_v", "<numbers>", cxx20}, -#line 378 "../../src/gcc/cp/std-name-hint.gperf" +#line 378 "std-name-hint.gperf" {"numbers::sqrt3_v", "<numbers>", cxx20}, -#line 242 "../../src/gcc/cp/std-name-hint.gperf" +#line 242 "std-name-hint.gperf" {"hexfloat", "<ios>", cxx11}, -#line 326 "../../src/gcc/cp/std-name-hint.gperf" +#line 326 "std-name-hint.gperf" {"shared_ptr", "<memory>", cxx11}, -#line 569 "../../src/gcc/cp/std-name-hint.gperf" +#line 569 "std-name-hint.gperf" {"integer_sequence", "<utility>", cxx14}, -#line 271 "../../src/gcc/cp/std-name-hint.gperf" +#line 271 "std-name-hint.gperf" {"istream", "<istream>", cxx98}, -#line 376 "../../src/gcc/cp/std-name-hint.gperf" +#line 376 "std-name-hint.gperf" {"numbers::pi_v", "<numbers>", cxx20}, -#line 259 "../../src/gcc/cp/std-name-hint.gperf" +#line 259 "std-name-hint.gperf" {"unitbuf", "<ios>", cxx98}, -#line 294 "../../src/gcc/cp/std-name-hint.gperf" +#line 294 "std-name-hint.gperf" {"list", "<list>", cxx98}, -#line 554 "../../src/gcc/cp/std-name-hint.gperf" +#line 554 "std-name-hint.gperf" {"cmp_less", "<utility>", cxx20}, -#line 422 "../../src/gcc/cp/std-name-hint.gperf" +#line 422 "std-name-hint.gperf" {"ispanstream", "<spanstream>", cxx23}, -#line 423 "../../src/gcc/cp/std-name-hint.gperf" +#line 423 "std-name-hint.gperf" {"ispanstream", "<spanstream>", cxx23}, -#line 470 "../../src/gcc/cp/std-name-hint.gperf" +#line 470 "std-name-hint.gperf" {"wstreambuf", "<streambuf>", cxx98}, -#line 432 "../../src/gcc/cp/std-name-hint.gperf" +#line 432 "std-name-hint.gperf" {"basic_ostringstream", "<sstream>", cxx98}, -#line 503 "../../src/gcc/cp/std-name-hint.gperf" +#line 503 "std-name-hint.gperf" {"make_error_condition", "<system_error>", cxx11}, -#line 570 "../../src/gcc/cp/std-name-hint.gperf" +#line 570 "std-name-hint.gperf" {"make_index_sequence", "<utility>", cxx14}, -#line 405 "../../src/gcc/cp/std-name-hint.gperf" +#line 405 "std-name-hint.gperf" {"counting_semaphore", "<semaphore>", cxx20}, -#line 355 "../../src/gcc/cp/std-name-hint.gperf" +#line 355 "std-name-hint.gperf" {"timed_mutex", "<mutex>", cxx11}, -#line 297 "../../src/gcc/cp/std-name-hint.gperf" +#line 297 "std-name-hint.gperf" {"multimap", "<map>", cxx98}, -#line 227 "../../src/gcc/cp/std-name-hint.gperf" +#line 227 "std-name-hint.gperf" {"put_money", "<iomanip>", cxx11}, -#line 309 "../../src/gcc/cp/std-name-hint.gperf" +#line 309 "std-name-hint.gperf" {"const_pointer_cast", "<memory>", cxx11}, -#line 45 "../../src/gcc/cp/std-name-hint.gperf" +#line 45 "std-name-hint.gperf" {"make_any", "<any>", cxx17}, -#line 465 "../../src/gcc/cp/std-name-hint.gperf" +#line 465 "std-name-hint.gperf" {"stop_source", "<stop_token>", cxx20}, -#line 548 "../../src/gcc/cp/std-name-hint.gperf" +#line 548 "std-name-hint.gperf" {"unordered_set", "<unordered_set>", cxx11}, -#line 582 "../../src/gcc/cp/std-name-hint.gperf" +#line 582 "std-name-hint.gperf" {"holds_alternative", "<variant>", cxx17}, -#line 514 "../../src/gcc/cp/std-name-hint.gperf" +#line 514 "std-name-hint.gperf" {"make_tuple", "<tuple>", cxx11}, -#line 47 "../../src/gcc/cp/std-name-hint.gperf" +#line 47 "std-name-hint.gperf" {"array", "<array>", cxx11}, -#line 517 "../../src/gcc/cp/std-name-hint.gperf" +#line 517 "std-name-hint.gperf" {"tuple_cat", "<tuple>", cxx11}, -#line 323 "../../src/gcc/cp/std-name-hint.gperf" +#line 323 "std-name-hint.gperf" {"owner_less", "<memory>", cxx11}, -#line 158 "../../src/gcc/cp/std-name-hint.gperf" +#line 158 "std-name-hint.gperf" {"exception", "<exception>", cxx98}, -#line 159 "../../src/gcc/cp/std-name-hint.gperf" +#line 159 "std-name-hint.gperf" {"exception_ptr", "<exception>", cxx11}, -#line 207 "../../src/gcc/cp/std-name-hint.gperf" +#line 207 "std-name-hint.gperf" {"hash", "<functional>", cxx11}, -#line 521 "../../src/gcc/cp/std-name-hint.gperf" +#line 521 "std-name-hint.gperf" {"tuple_size_v", "<tuple>", cxx17}, -#line 431 "../../src/gcc/cp/std-name-hint.gperf" +#line 431 "std-name-hint.gperf" {"basic_istringstream", "<sstream>", cxx98}, -#line 153 "../../src/gcc/cp/std-name-hint.gperf" +#line 153 "std-name-hint.gperf" {"uintptr_t", "<cstdint>", cxx11}, -#line 476 "../../src/gcc/cp/std-name-hint.gperf" +#line 476 "std-name-hint.gperf" {"stoi", "<string>", cxx11}, -#line 466 "../../src/gcc/cp/std-name-hint.gperf" +#line 466 "std-name-hint.gperf" {"stop_token", "<stop_token>", cxx20}, -#line 151 "../../src/gcc/cp/std-name-hint.gperf" +#line 151 "std-name-hint.gperf" {"uint_least8_t", "<cstdint>", cxx11}, -#line 380 "../../src/gcc/cp/std-name-hint.gperf" +#line 380 "std-name-hint.gperf" {"make_optional", "<optional>", cxx17}, -#line 345 "../../src/gcc/cp/std-name-hint.gperf" +#line 345 "std-name-hint.gperf" {"pmr::unsynchronized_pool_resource", "<memory_resource>", cxx17}, -#line 48 "../../src/gcc/cp/std-name-hint.gperf" +#line 48 "std-name-hint.gperf" {"to_array", "<array>", cxx20}, -#line 104 "../../src/gcc/cp/std-name-hint.gperf" +#line 104 "std-name-hint.gperf" {"complex_literals", "<complex>", cxx14}, -#line 411 "../../src/gcc/cp/std-name-hint.gperf" +#line 411 "std-name-hint.gperf" {"shared_mutex", "<shared_mutex>", cxx17}, -#line 375 "../../src/gcc/cp/std-name-hint.gperf" +#line 375 "std-name-hint.gperf" {"numbers::phi_v", "<numbers>", cxx20}, -#line 499 "../../src/gcc/cp/std-name-hint.gperf" +#line 499 "std-name-hint.gperf" {"is_error_code_enum_v", "<system_error>", cxx17}, -#line 155 "../../src/gcc/cp/std-name-hint.gperf" +#line 155 "std-name-hint.gperf" {"deque", "<deque>", cxx98}, -#line 412 "../../src/gcc/cp/std-name-hint.gperf" +#line 412 "std-name-hint.gperf" {"shared_timed_mutex", "<shared_mutex>", cxx14}, -#line 290 "../../src/gcc/cp/std-name-hint.gperf" +#line 290 "std-name-hint.gperf" {"ostreambuf_iterator", "<iterator>", cxx98}, -#line 501 "../../src/gcc/cp/std-name-hint.gperf" +#line 501 "std-name-hint.gperf" {"is_error_condition_enum_v", "<system_error>", cxx17}, -#line 148 "../../src/gcc/cp/std-name-hint.gperf" +#line 148 "std-name-hint.gperf" {"uint_least16_t", "<cstdint>", cxx11}, -#line 305 "../../src/gcc/cp/std-name-hint.gperf" +#line 305 "std-name-hint.gperf" {"allocator_arg_t", "<memory>", cxx11}, -#line 366 "../../src/gcc/cp/std-name-hint.gperf" +#line 366 "std-name-hint.gperf" {"numbers::e_v", "<numbers>", cxx20}, -#line 209 "../../src/gcc/cp/std-name-hint.gperf" +#line 209 "std-name-hint.gperf" {"invoke_r", "<functional>", cxx23}, -#line 441 "../../src/gcc/cp/std-name-hint.gperf" +#line 441 "std-name-hint.gperf" {"wostringstream", "<sstream>", cxx98}, -#line 122 "../../src/gcc/cp/std-name-hint.gperf" +#line 122 "std-name-hint.gperf" {"copy_constructible", "<concepts>", cxx20}, -#line 149 "../../src/gcc/cp/std-name-hint.gperf" +#line 149 "std-name-hint.gperf" {"uint_least32_t", "<cstdint>", cxx11}, -#line 108 "../../src/gcc/cp/std-name-hint.gperf" +#line 108 "std-name-hint.gperf" {"convertible_to", "<concepts>", cxx20}, -#line 234 "../../src/gcc/cp/std-name-hint.gperf" +#line 234 "std-name-hint.gperf" {"setprecision", "<iomanip>", cxx98}, -#line 498 "../../src/gcc/cp/std-name-hint.gperf" +#line 498 "std-name-hint.gperf" {"is_error_code_enum", "<system_error>", cxx11}, -#line 453 "../../src/gcc/cp/std-name-hint.gperf" +#line 453 "std-name-hint.gperf" {"overflow_error", "<stdexcept>", cxx98}, -#line 414 "../../src/gcc/cp/std-name-hint.gperf" +#line 414 "std-name-hint.gperf" {"source_location", "<source_location>", cxx20}, -#line 500 "../../src/gcc/cp/std-name-hint.gperf" +#line 500 "std-name-hint.gperf" {"is_error_condition_enum", "<system_error>", cxx11}, -#line 400 "../../src/gcc/cp/std-name-hint.gperf" +#line 400 "std-name-hint.gperf" {"ranges::enable_view", "<ranges>", cxx20}, -#line 218 "../../src/gcc/cp/std-name-hint.gperf" +#line 218 "std-name-hint.gperf" {"async", "<future>", cxx11}, -#line 103 "../../src/gcc/cp/std-name-hint.gperf" +#line 103 "std-name-hint.gperf" {"complex", "<complex>", cxx98}, -#line 150 "../../src/gcc/cp/std-name-hint.gperf" +#line 150 "std-name-hint.gperf" {"uint_least64_t", "<cstdint>", cxx11}, -#line 232 "../../src/gcc/cp/std-name-hint.gperf" +#line 232 "std-name-hint.gperf" {"setfill", "<iomanip>", cxx98}, -#line 79 "../../src/gcc/cp/std-name-hint.gperf" +#line 79 "std-name-hint.gperf" {"chrono::parse", "<chrono>", cxx20}, -#line 285 "../../src/gcc/cp/std-name-hint.gperf" +#line 285 "std-name-hint.gperf" {"istreambuf_iterator", "<iterator>", cxx98}, -#line 473 "../../src/gcc/cp/std-name-hint.gperf" +#line 473 "std-name-hint.gperf" {"char_traits", "<string>", cxx98}, -#line 263 "../../src/gcc/cp/std-name-hint.gperf" +#line 263 "std-name-hint.gperf" {"cin", "<iostream>", cxx98}, -#line 61 "../../src/gcc/cp/std-name-hint.gperf" +#line 61 "std-name-hint.gperf" {"chrono::duration_cast", "<chrono>", cxx11}, -#line 152 "../../src/gcc/cp/std-name-hint.gperf" +#line 152 "std-name-hint.gperf" {"uintmax_t", "<cstdint>", cxx11}, -#line 43 "../../src/gcc/cp/std-name-hint.gperf" +#line 43 "std-name-hint.gperf" {"any", "<any>", cxx17}, -#line 389 "../../src/gcc/cp/std-name-hint.gperf" +#line 389 "std-name-hint.gperf" {"noemit_on_flush", "<ostream>", cxx20}, -#line 66 "../../src/gcc/cp/std-name-hint.gperf" +#line 66 "std-name-hint.gperf" {"chrono::get_tzdb_list", "<chrono>", cxx20}, -#line 93 "../../src/gcc/cp/std-name-hint.gperf" +#line 93 "std-name-hint.gperf" {"chrono::weeks", "<chrono>", cxx20}, -#line 65 "../../src/gcc/cp/std-name-hint.gperf" +#line 65 "std-name-hint.gperf" {"chrono::get_tzdb", "<chrono>", cxx20}, -#line 302 "../../src/gcc/cp/std-name-hint.gperf" +#line 302 "std-name-hint.gperf" {"allocate_shared_for_overwrite", "<memory>", cxx20}, -#line 547 "../../src/gcc/cp/std-name-hint.gperf" +#line 547 "std-name-hint.gperf" {"unordered_multiset", "<unordered_set>", cxx11}, -#line 194 "../../src/gcc/cp/std-name-hint.gperf" +#line 194 "std-name-hint.gperf" {"forward_list", "<forward_list>", cxx11}, -#line 496 "../../src/gcc/cp/std-name-hint.gperf" +#line 496 "std-name-hint.gperf" {"error_condition", "<system_error>", cxx11}, -#line 542 "../../src/gcc/cp/std-name-hint.gperf" +#line 542 "std-name-hint.gperf" {"bad_typeid", "<typeinfo>", cxx98}, -#line 60 "../../src/gcc/cp/std-name-hint.gperf" +#line 60 "std-name-hint.gperf" {"chrono::duration", "<chrono>", cxx11}, -#line 510 "../../src/gcc/cp/std-name-hint.gperf" +#line 510 "std-name-hint.gperf" {"apply", "<tuple>", cxx17}, -#line 95 "../../src/gcc/cp/std-name-hint.gperf" +#line 95 "std-name-hint.gperf" {"chrono::zoned_time", "<chrono>", cxx20}, -#line 477 "../../src/gcc/cp/std-name-hint.gperf" +#line 477 "std-name-hint.gperf" {"stol", "<string>", cxx11}, -#line 479 "../../src/gcc/cp/std-name-hint.gperf" +#line 479 "std-name-hint.gperf" {"stoll", "<string>", cxx11}, -#line 480 "../../src/gcc/cp/std-name-hint.gperf" +#line 480 "std-name-hint.gperf" {"stoul", "<string>", cxx11}, -#line 481 "../../src/gcc/cp/std-name-hint.gperf" +#line 481 "std-name-hint.gperf" {"stoull", "<string>", cxx11}, -#line 220 "../../src/gcc/cp/std-name-hint.gperf" +#line 220 "std-name-hint.gperf" {"packaged_task", "<future>", cxx11}, -#line 544 "../../src/gcc/cp/std-name-hint.gperf" +#line 544 "std-name-hint.gperf" {"unordered_map", "<unordered_map>", cxx11}, -#line 77 "../../src/gcc/cp/std-name-hint.gperf" +#line 77 "std-name-hint.gperf" {"chrono::months", "<chrono>", cxx20}, -#line 76 "../../src/gcc/cp/std-name-hint.gperf" +#line 76 "std-name-hint.gperf" {"chrono::minutes", "<chrono>", cxx11}, -#line 545 "../../src/gcc/cp/std-name-hint.gperf" +#line 545 "std-name-hint.gperf" {"unordered_multimap", "<unordered_map>", cxx11}, -#line 78 "../../src/gcc/cp/std-name-hint.gperf" +#line 78 "std-name-hint.gperf" {"chrono::nanoseconds", "<chrono>", cxx11}, -#line 286 "../../src/gcc/cp/std-name-hint.gperf" +#line 286 "std-name-hint.gperf" {"iterator_traits", "<iterator>", cxx98}, -#line 404 "../../src/gcc/cp/std-name-hint.gperf" +#line 404 "std-name-hint.gperf" {"binary_semaphore", "<semaphore>", cxx20}, -#line 281 "../../src/gcc/cp/std-name-hint.gperf" +#line 281 "std-name-hint.gperf" {"end", "<iterator>", cxx11}, -#line 429 "../../src/gcc/cp/std-name-hint.gperf" +#line 429 "std-name-hint.gperf" {"wspanbuf", "<spanstream>", cxx23}, -#line 252 "../../src/gcc/cp/std-name-hint.gperf" +#line 252 "std-name-hint.gperf" {"oct", "<ios>", cxx98}, -#line 245 "../../src/gcc/cp/std-name-hint.gperf" +#line 245 "std-name-hint.gperf" {"noboolalpha", "<ios>", cxx98}, -#line 450 "../../src/gcc/cp/std-name-hint.gperf" +#line 450 "std-name-hint.gperf" {"length_error", "<stdexcept>", cxx98}, -#line 560 "../../src/gcc/cp/std-name-hint.gperf" +#line 560 "std-name-hint.gperf" {"in_place", "<utility>", cxx17}, -#line 563 "../../src/gcc/cp/std-name-hint.gperf" +#line 563 "std-name-hint.gperf" {"in_place_t", "<utility>", cxx17}, -#line 384 "../../src/gcc/cp/std-name-hint.gperf" +#line 384 "std-name-hint.gperf" {"emit_on_flush", "<ostream>", cxx20}, -#line 440 "../../src/gcc/cp/std-name-hint.gperf" +#line 440 "std-name-hint.gperf" {"wistringstream", "<sstream>", cxx98}, -#line 327 "../../src/gcc/cp/std-name-hint.gperf" +#line 327 "std-name-hint.gperf" {"static_pointer_cast", "<memory>", cxx11}, -#line 260 "../../src/gcc/cp/std-name-hint.gperf" +#line 260 "std-name-hint.gperf" {"uppercase", "<ios>", cxx98}, -#line 277 "../../src/gcc/cp/std-name-hint.gperf" +#line 277 "std-name-hint.gperf" {"common_iterator", "<iterator>", cxx20}, -#line 117 "../../src/gcc/cp/std-name-hint.gperf" +#line 117 "std-name-hint.gperf" {"swappable_with", "<concepts>", cxx20}, -#line 359 "../../src/gcc/cp/std-name-hint.gperf" +#line 359 "std-name-hint.gperf" {"bad_alloc", "<new>", cxx98}, -#line 391 "../../src/gcc/cp/std-name-hint.gperf" +#line 391 "std-name-hint.gperf" {"wostream", "<ostream>", cxx98}, -#line 348 "../../src/gcc/cp/std-name-hint.gperf" +#line 348 "std-name-hint.gperf" {"lock", "<mutex>", cxx11}, -#line 504 "../../src/gcc/cp/std-name-hint.gperf" +#line 504 "std-name-hint.gperf" {"system_category", "<system_error>", cxx11}, -#line 128 "../../src/gcc/cp/std-name-hint.gperf" +#line 128 "std-name-hint.gperf" {"copyable", "<concepts>", cxx20}, -#line 139 "../../src/gcc/cp/std-name-hint.gperf" +#line 139 "std-name-hint.gperf" {"condition_variable", "<condition_variable>", cxx11}, -#line 240 "../../src/gcc/cp/std-name-hint.gperf" +#line 240 "std-name-hint.gperf" {"fixed", "<ios>", cxx98}, -#line 553 "../../src/gcc/cp/std-name-hint.gperf" +#line 553 "std-name-hint.gperf" {"cmp_greater_equal", "<utility>", cxx20}, -#line 508 "../../src/gcc/cp/std-name-hint.gperf" +#line 508 "std-name-hint.gperf" {"thread", "<thread>", cxx11}, -#line 439 "../../src/gcc/cp/std-name-hint.gperf" +#line 439 "std-name-hint.gperf" {"stringstream", "<sstream>", cxx98}, -#line 58 "../../src/gcc/cp/std-name-hint.gperf" +#line 58 "std-name-hint.gperf" {"chrono::clock_cast", "<chrono>", cxx20}, -#line 579 "../../src/gcc/cp/std-name-hint.gperf" +#line 579 "std-name-hint.gperf" {"unreachable", "<utility>", cxx23}, -#line 428 "../../src/gcc/cp/std-name-hint.gperf" +#line 428 "std-name-hint.gperf" {"wospanstream", "<spanstream>", cxx23}, -#line 330 "../../src/gcc/cp/std-name-hint.gperf" +#line 330 "std-name-hint.gperf" {"unique_ptr", "<memory>", cxx11}, -#line 562 "../../src/gcc/cp/std-name-hint.gperf" +#line 562 "std-name-hint.gperf" {"in_place_index_t", "<utility>", cxx17}, -#line 363 "../../src/gcc/cp/std-name-hint.gperf" +#line 363 "std-name-hint.gperf" {"nothrow", "<new>", cxx98}, -#line 64 "../../src/gcc/cp/std-name-hint.gperf" +#line 64 "std-name-hint.gperf" {"chrono::get_leap_second_info", "<chrono>", cxx20}, -#line 204 "../../src/gcc/cp/std-name-hint.gperf" +#line 204 "std-name-hint.gperf" {"bind", "<functional>", cxx11}, -#line 89 "../../src/gcc/cp/std-name-hint.gperf" +#line 89 "std-name-hint.gperf" {"chrono::time_zone", "<chrono>", cxx20}, -#line 120 "../../src/gcc/cp/std-name-hint.gperf" +#line 120 "std-name-hint.gperf" {"default_initializable", "<concepts>", cxx20}, -#line 145 "../../src/gcc/cp/std-name-hint.gperf" +#line 145 "std-name-hint.gperf" {"uint_fast32_t", "<cstdint>", cxx11}, -#line 87 "../../src/gcc/cp/std-name-hint.gperf" +#line 87 "std-name-hint.gperf" {"chrono::time_point", "<chrono>", cxx11}, -#line 444 "../../src/gcc/cp/std-name-hint.gperf" +#line 444 "std-name-hint.gperf" {"stack", "<stack>", cxx98}, -#line 215 "../../src/gcc/cp/std-name-hint.gperf" +#line 215 "std-name-hint.gperf" {"unwrap_reference", "<functional>", cxx20}, -#line 88 "../../src/gcc/cp/std-name-hint.gperf" +#line 88 "std-name-hint.gperf" {"chrono::time_point_cast", "<chrono>", cxx11}, -#line 223 "../../src/gcc/cp/std-name-hint.gperf" +#line 223 "std-name-hint.gperf" {"generator", "<generator>", cxx23}, -#line 216 "../../src/gcc/cp/std-name-hint.gperf" +#line 216 "std-name-hint.gperf" {"unwrap_reference_t", "<functional>", cxx20}, -#line 382 "../../src/gcc/cp/std-name-hint.gperf" +#line 382 "std-name-hint.gperf" {"optional", "<optional>", cxx17}, -#line 112 "../../src/gcc/cp/std-name-hint.gperf" +#line 112 "std-name-hint.gperf" {"signed_integral", "<concepts>", cxx20}, -#line 456 "../../src/gcc/cp/std-name-hint.gperf" +#line 456 "std-name-hint.gperf" {"underflow_error", "<stdexcept>", cxx98}, -#line 239 "../../src/gcc/cp/std-name-hint.gperf" +#line 239 "std-name-hint.gperf" {"defaultfloat", "<ios>", cxx11}, -#line 146 "../../src/gcc/cp/std-name-hint.gperf" +#line 146 "std-name-hint.gperf" {"uint_fast64_t", "<cstdint>", cxx11}, -#line 129 "../../src/gcc/cp/std-name-hint.gperf" +#line 129 "std-name-hint.gperf" {"semiregular", "<concepts>", cxx20}, -#line 111 "../../src/gcc/cp/std-name-hint.gperf" +#line 111 "std-name-hint.gperf" {"integral", "<concepts>", cxx20}, -#line 243 "../../src/gcc/cp/std-name-hint.gperf" +#line 243 "std-name-hint.gperf" {"internal", "<ios>", cxx98}, -#line 144 "../../src/gcc/cp/std-name-hint.gperf" +#line 144 "std-name-hint.gperf" {"uint_fast16_t", "<cstdint>", cxx11}, -#line 329 "../../src/gcc/cp/std-name-hint.gperf" +#line 329 "std-name-hint.gperf" {"uninitialized_construct_using_allocator", "<memory>", cxx20}, -#line 81 "../../src/gcc/cp/std-name-hint.gperf" +#line 81 "std-name-hint.gperf" {"chrono::remote_version", "<chrono>", cxx20}, -#line 458 "../../src/gcc/cp/std-name-hint.gperf" +#line 458 "std-name-hint.gperf" {"bfloat16_t", "<stdfloat>", cxx23}, -#line 576 "../../src/gcc/cp/std-name-hint.gperf" +#line 576 "std-name-hint.gperf" {"piecewise_construct", "<utility>", cxx11}, -#line 577 "../../src/gcc/cp/std-name-hint.gperf" +#line 577 "std-name-hint.gperf" {"piecewise_construct_t", "<utility>", cxx11}, -#line 278 "../../src/gcc/cp/std-name-hint.gperf" +#line 278 "std-name-hint.gperf" {"const_iterator", "<iterator>", cxx23}, -#line 484 "../../src/gcc/cp/std-name-hint.gperf" +#line 484 "std-name-hint.gperf" {"to_wstring", "<string>", cxx17}, -#line 356 "../../src/gcc/cp/std-name-hint.gperf" +#line 356 "std-name-hint.gperf" {"try_lock", "<mutex>", cxx11}, -#line 561 "../../src/gcc/cp/std-name-hint.gperf" +#line 561 "std-name-hint.gperf" {"in_place_index", "<utility>", cxx17}, -#line 51 "../../src/gcc/cp/std-name-hint.gperf" +#line 51 "std-name-hint.gperf" {"atomic_ref", "<atomic>", cxx20}, -#line 113 "../../src/gcc/cp/std-name-hint.gperf" +#line 113 "std-name-hint.gperf" {"unsigned_integral", "<concepts>", cxx20}, -#line 94 "../../src/gcc/cp/std-name-hint.gperf" +#line 94 "std-name-hint.gperf" {"chrono::years", "<chrono>", cxx20}, -#line 229 "../../src/gcc/cp/std-name-hint.gperf" +#line 229 "std-name-hint.gperf" {"quoted", "<iomanip>", cxx14}, -#line 115 "../../src/gcc/cp/std-name-hint.gperf" +#line 115 "std-name-hint.gperf" {"assignable_from", "<concepts>", cxx20}, -#line 53 "../../src/gcc/cp/std-name-hint.gperf" +#line 53 "std-name-hint.gperf" {"atomic_uintmax_t", "<atomic>", cxx20}, -#line 162 "../../src/gcc/cp/std-name-hint.gperf" +#line 162 "std-name-hint.gperf" {"uncaught_exceptions", "<exception>", cxx17}, -#line 331 "../../src/gcc/cp/std-name-hint.gperf" +#line 331 "std-name-hint.gperf" {"uses_allocator", "<memory>", cxx11}, -#line 472 "../../src/gcc/cp/std-name-hint.gperf" +#line 472 "std-name-hint.gperf" {"basic_string", "<string>", cxx98}, -#line 311 "../../src/gcc/cp/std-name-hint.gperf" +#line 311 "std-name-hint.gperf" {"default_delete", "<memory>", cxx11}, -#line 164 "../../src/gcc/cp/std-name-hint.gperf" +#line 164 "std-name-hint.gperf" {"expected", "<expected>", cxx23}, -#line 313 "../../src/gcc/cp/std-name-hint.gperf" +#line 313 "std-name-hint.gperf" {"destroy_at", "<memory>", cxx20}, -#line 536 "../../src/gcc/cp/std-name-hint.gperf" +#line 536 "std-name-hint.gperf" {"type_identity_t", "<type_traits>", cxx20}, -#line 63 "../../src/gcc/cp/std-name-hint.gperf" +#line 63 "std-name-hint.gperf" {"chrono::from_stream", "<chrono>", cxx20}, -#line 427 "../../src/gcc/cp/std-name-hint.gperf" +#line 427 "std-name-hint.gperf" {"wispanstream", "<spanstream>", cxx23}, -#line 52 "../../src/gcc/cp/std-name-hint.gperf" +#line 52 "std-name-hint.gperf" {"atomic_signed_lock_free", "<atomic>", cxx11}, -#line 266 "../../src/gcc/cp/std-name-hint.gperf" +#line 266 "std-name-hint.gperf" {"wcerr", "<iostream>", cxx98}, -#line 511 "../../src/gcc/cp/std-name-hint.gperf" +#line 511 "std-name-hint.gperf" {"forward_as_tuple", "<tuple>", cxx11}, -#line 187 "../../src/gcc/cp/std-name-hint.gperf" +#line 187 "std-name-hint.gperf" {"vformat", "<format>", cxx20}, -#line 332 "../../src/gcc/cp/std-name-hint.gperf" +#line 332 "std-name-hint.gperf" {"uses_allocator_construction_args", "<memory>", cxx20}, -#line 269 "../../src/gcc/cp/std-name-hint.gperf" +#line 269 "std-name-hint.gperf" {"wcout", "<iostream>", cxx98}, -#line 314 "../../src/gcc/cp/std-name-hint.gperf" +#line 314 "std-name-hint.gperf" {"destroy_n", "<memory>", cxx20}, -#line 226 "../../src/gcc/cp/std-name-hint.gperf" +#line 226 "std-name-hint.gperf" {"get_time", "<iomanip>", cxx11}, -#line 555 "../../src/gcc/cp/std-name-hint.gperf" +#line 555 "std-name-hint.gperf" {"cmp_less_equal", "<utility>", cxx20}, -#line 80 "../../src/gcc/cp/std-name-hint.gperf" +#line 80 "std-name-hint.gperf" {"chrono::reload_tzdb", "<chrono>", cxx20}, -#line 523 "../../src/gcc/cp/std-name-hint.gperf" +#line 523 "std-name-hint.gperf" {"conjunction", "<type_traits>", cxx17}, -#line 75 "../../src/gcc/cp/std-name-hint.gperf" +#line 75 "std-name-hint.gperf" {"chrono::milliseconds", "<chrono>", cxx11}, -#line 59 "../../src/gcc/cp/std-name-hint.gperf" +#line 59 "std-name-hint.gperf" {"chrono::days", "<chrono>", cxx20}, -#line 474 "../../src/gcc/cp/std-name-hint.gperf" +#line 474 "std-name-hint.gperf" {"stod", "<string>", cxx11}, -#line 478 "../../src/gcc/cp/std-name-hint.gperf" +#line 478 "std-name-hint.gperf" {"stold", "<string>", cxx11}, -#line 267 "../../src/gcc/cp/std-name-hint.gperf" +#line 267 "std-name-hint.gperf" {"wcin", "<iostream>", cxx98}, -#line 529 "../../src/gcc/cp/std-name-hint.gperf" +#line 529 "std-name-hint.gperf" {"invoke_result", "<type_traits>", cxx17}, -#line 530 "../../src/gcc/cp/std-name-hint.gperf" +#line 530 "std-name-hint.gperf" {"invoke_result_t", "<type_traits>", cxx17}, -#line 50 "../../src/gcc/cp/std-name-hint.gperf" +#line 50 "std-name-hint.gperf" {"atomic", "<atomic>", cxx11}, -#line 71 "../../src/gcc/cp/std-name-hint.gperf" +#line 71 "std-name-hint.gperf" {"chrono::leap_second_info", "<chrono>", cxx20}, -#line 238 "../../src/gcc/cp/std-name-hint.gperf" +#line 238 "std-name-hint.gperf" {"dec", "<ios>", cxx98}, -#line 157 "../../src/gcc/cp/std-name-hint.gperf" +#line 157 "std-name-hint.gperf" {"current_exception", "<exception>", cxx11}, -#line 119 "../../src/gcc/cp/std-name-hint.gperf" +#line 119 "std-name-hint.gperf" {"constructible_from", "<concepts>", cxx20}, -#line 100 "../../src/gcc/cp/std-name-hint.gperf" +#line 100 "std-name-hint.gperf" {"weak_equality", "<compare>", cxx20}, -#line 333 "../../src/gcc/cp/std-name-hint.gperf" +#line 333 "std-name-hint.gperf" {"uses_allocator_v", "<memory>", cxx17}, -#line 69 "../../src/gcc/cp/std-name-hint.gperf" +#line 69 "std-name-hint.gperf" {"chrono::hours", "<chrono>", cxx11}, -#line 109 "../../src/gcc/cp/std-name-hint.gperf" +#line 109 "std-name-hint.gperf" {"common_reference_with", "<concepts>", cxx20}, -#line 483 "../../src/gcc/cp/std-name-hint.gperf" +#line 483 "std-name-hint.gperf" {"to_string", "<string>", cxx17}, -#line 524 "../../src/gcc/cp/std-name-hint.gperf" +#line 524 "std-name-hint.gperf" {"conjunction_v", "<type_traits>", cxx17}, -#line 578 "../../src/gcc/cp/std-name-hint.gperf" +#line 578 "std-name-hint.gperf" {"to_underlying", "<utility>", cxx23}, -#line 402 "../../src/gcc/cp/std-name-hint.gperf" +#line 402 "std-name-hint.gperf" {"scoped_allocator_adaptor", "<scoped_allocator>", cxx11}, -#line 310 "../../src/gcc/cp/std-name-hint.gperf" +#line 310 "std-name-hint.gperf" {"construct_at", "<memory>", cxx20}, -#line 564 "../../src/gcc/cp/std-name-hint.gperf" +#line 564 "std-name-hint.gperf" {"in_place_type", "<utility>", cxx17}, -#line 320 "../../src/gcc/cp/std-name-hint.gperf" +#line 320 "std-name-hint.gperf" {"make_shared_for_overwrite", "<memory>", cxx20}, -#line 166 "../../src/gcc/cp/std-name-hint.gperf" +#line 166 "std-name-hint.gperf" {"basic_format_arg", "<format>", cxx20}, -#line 73 "../../src/gcc/cp/std-name-hint.gperf" +#line 73 "std-name-hint.gperf" {"chrono::locate_zone", "<chrono>", cxx20}, -#line 72 "../../src/gcc/cp/std-name-hint.gperf" +#line 72 "std-name-hint.gperf" {"chrono::local_t", "<chrono>", cxx20}, -#line 170 "../../src/gcc/cp/std-name-hint.gperf" +#line 170 "std-name-hint.gperf" {"basic_format_string", "<format>", cxx20}, -#line 565 "../../src/gcc/cp/std-name-hint.gperf" +#line 565 "std-name-hint.gperf" {"in_place_type_t", "<utility>", cxx17}, -#line 279 "../../src/gcc/cp/std-name-hint.gperf" +#line 279 "std-name-hint.gperf" {"counted_iterator", "<iterator>", cxx20}, -#line 448 "../../src/gcc/cp/std-name-hint.gperf" +#line 448 "std-name-hint.gperf" {"domain_error", "<stdexcept>", cxx98}, -#line 84 "../../src/gcc/cp/std-name-hint.gperf" +#line 84 "std-name-hint.gperf" {"chrono::steady_clock", "<chrono>", cxx11}, -#line 188 "../../src/gcc/cp/std-name-hint.gperf" +#line 188 "std-name-hint.gperf" {"vformat_to", "<format>", cxx20}, -#line 54 "../../src/gcc/cp/std-name-hint.gperf" +#line 54 "std-name-hint.gperf" {"atomic_unsigned_lock_free", "<atomic>", cxx11}, -#line 147 "../../src/gcc/cp/std-name-hint.gperf" +#line 147 "std-name-hint.gperf" {"uint_fast8_t", "<cstdint>", cxx11}, -#line 83 "../../src/gcc/cp/std-name-hint.gperf" +#line 83 "std-name-hint.gperf" {"chrono::seconds", "<chrono>", cxx11}, -#line 74 "../../src/gcc/cp/std-name-hint.gperf" +#line 74 "std-name-hint.gperf" {"chrono::microseconds", "<chrono>", cxx11}, -#line 67 "../../src/gcc/cp/std-name-hint.gperf" +#line 67 "std-name-hint.gperf" {"chrono::gps_clock", "<chrono>", cxx20}, -#line 85 "../../src/gcc/cp/std-name-hint.gperf" +#line 85 "std-name-hint.gperf" {"chrono::system_clock", "<chrono>", cxx11}, -#line 140 "../../src/gcc/cp/std-name-hint.gperf" +#line 140 "std-name-hint.gperf" {"condition_variable_any", "<condition_variable>", cxx11}, -#line 214 "../../src/gcc/cp/std-name-hint.gperf" +#line 214 "std-name-hint.gperf" {"unwrap_ref_decay_t", "<functional>", cxx20}, -#line 136 "../../src/gcc/cp/std-name-hint.gperf" +#line 136 "std-name-hint.gperf" {"strict_weak_order", "<concepts>", cxx20}, -#line 437 "../../src/gcc/cp/std-name-hint.gperf" +#line 437 "std-name-hint.gperf" {"ostringstream", "<sstream>", cxx98}, -#line 317 "../../src/gcc/cp/std-name-hint.gperf" +#line 317 "std-name-hint.gperf" {"get_deleter", "<memory>", cxx11}, -#line 367 "../../src/gcc/cp/std-name-hint.gperf" +#line 367 "std-name-hint.gperf" {"numbers::egamma_v", "<numbers>", cxx20}, -#line 566 "../../src/gcc/cp/std-name-hint.gperf" +#line 566 "std-name-hint.gperf" {"in_range", "<utility>", cxx20}, -#line 558 "../../src/gcc/cp/std-name-hint.gperf" +#line 558 "std-name-hint.gperf" {"exchange", "<utility>", cxx14}, -#line 551 "../../src/gcc/cp/std-name-hint.gperf" +#line 551 "std-name-hint.gperf" {"cmp_equal", "<utility>", cxx20}, -#line 556 "../../src/gcc/cp/std-name-hint.gperf" +#line 556 "std-name-hint.gperf" {"cmp_not_equal", "<utility>", cxx20}, -#line 435 "../../src/gcc/cp/std-name-hint.gperf" +#line 435 "std-name-hint.gperf" {"istringstream", "<sstream>", cxx98}, -#line 436 "../../src/gcc/cp/std-name-hint.gperf" +#line 436 "std-name-hint.gperf" {"istringstream", "<sstream>", cxx98}, -#line 442 "../../src/gcc/cp/std-name-hint.gperf" +#line 442 "std-name-hint.gperf" {"wstringbuf", "<sstream>", cxx98}, -#line 225 "../../src/gcc/cp/std-name-hint.gperf" +#line 225 "std-name-hint.gperf" {"get_money", "<iomanip>", cxx11}, -#line 191 "../../src/gcc/cp/std-name-hint.gperf" +#line 191 "std-name-hint.gperf" {"wformat_parse_context", "<format>", cxx20}, -#line 482 "../../src/gcc/cp/std-name-hint.gperf" +#line 482 "std-name-hint.gperf" {"string", "<string>", cxx98}, -#line 280 "../../src/gcc/cp/std-name-hint.gperf" +#line 280 "std-name-hint.gperf" {"distance", "<iterator>", cxx98}, -#line 557 "../../src/gcc/cp/std-name-hint.gperf" +#line 557 "std-name-hint.gperf" {"declval", "<utility>", cxx11}, -#line 254 "../../src/gcc/cp/std-name-hint.gperf" +#line 254 "std-name-hint.gperf" {"scientific", "<ios>", cxx98}, -#line 98 "../../src/gcc/cp/std-name-hint.gperf" +#line 98 "std-name-hint.gperf" {"strong_equality", "<compare>", cxx20}, -#line 487 "../../src/gcc/cp/std-name-hint.gperf" +#line 487 "std-name-hint.gperf" {"u8string", "<string>", cxx20}, -#line 190 "../../src/gcc/cp/std-name-hint.gperf" +#line 190 "std-name-hint.gperf" {"wformat_context", "<format>", cxx20}, -#line 312 "../../src/gcc/cp/std-name-hint.gperf" +#line 312 "std-name-hint.gperf" {"destroy", "<memory>", cxx20}, -#line 559 "../../src/gcc/cp/std-name-hint.gperf" +#line 559 "std-name-hint.gperf" {"forward", "<utility>", cxx11}, -#line 535 "../../src/gcc/cp/std-name-hint.gperf" +#line 535 "std-name-hint.gperf" {"type_identity", "<type_traits>", cxx20}, -#line 464 "../../src/gcc/cp/std-name-hint.gperf" +#line 464 "std-name-hint.gperf" {"stop_callback", "<stop_token>", cxx20}, -#line 86 "../../src/gcc/cp/std-name-hint.gperf" +#line 86 "std-name-hint.gperf" {"chrono::tai_clock", "<chrono>", cxx20}, -#line 91 "../../src/gcc/cp/std-name-hint.gperf" +#line 91 "std-name-hint.gperf" {"chrono::tzdb_list", "<chrono>", cxx20}, -#line 301 "../../src/gcc/cp/std-name-hint.gperf" +#line 301 "std-name-hint.gperf" {"allocate_shared", "<memory>", cxx11}, -#line 90 "../../src/gcc/cp/std-name-hint.gperf" +#line 90 "std-name-hint.gperf" {"chrono::tzdb", "<chrono>", cxx20}, -#line 126 "../../src/gcc/cp/std-name-hint.gperf" +#line 126 "std-name-hint.gperf" {"totally_ordered_with", "<concepts>", cxx20}, -#line 525 "../../src/gcc/cp/std-name-hint.gperf" +#line 525 "std-name-hint.gperf" {"disjunction", "<type_traits>", cxx17}, -#line 110 "../../src/gcc/cp/std-name-hint.gperf" +#line 110 "std-name-hint.gperf" {"common_with", "<concepts>", cxx20}, -#line 202 "../../src/gcc/cp/std-name-hint.gperf" +#line 202 "std-name-hint.gperf" {"ofstream", "<fstream>", cxx98}, -#line 349 "../../src/gcc/cp/std-name-hint.gperf" +#line 349 "std-name-hint.gperf" {"lock_guard", "<mutex>", cxx11}, -#line 118 "../../src/gcc/cp/std-name-hint.gperf" +#line 118 "std-name-hint.gperf" {"destructible", "<concepts>", cxx20}, -#line 176 "../../src/gcc/cp/std-name-hint.gperf" +#line 176 "std-name-hint.gperf" {"format_string", "<format>", cxx20}, -#line 410 "../../src/gcc/cp/std-name-hint.gperf" +#line 410 "std-name-hint.gperf" {"shared_lock", "<shared_mutex>", cxx14}, -#line 315 "../../src/gcc/cp/std-name-hint.gperf" +#line 315 "std-name-hint.gperf" {"dynamic_pointer_cast", "<memory>", cxx11}, -#line 101 "../../src/gcc/cp/std-name-hint.gperf" +#line 101 "std-name-hint.gperf" {"weak_ordering", "<compare>", cxx20}, -#line 201 "../../src/gcc/cp/std-name-hint.gperf" +#line 201 "std-name-hint.gperf" {"ifstream", "<fstream>", cxx98}, -#line 452 "../../src/gcc/cp/std-name-hint.gperf" +#line 452 "std-name-hint.gperf" {"out_of_range", "<stdexcept>", cxx98}, -#line 264 "../../src/gcc/cp/std-name-hint.gperf" +#line 264 "std-name-hint.gperf" {"clog", "<iostream>", cxx98}, -#line 62 "../../src/gcc/cp/std-name-hint.gperf" +#line 62 "std-name-hint.gperf" {"chrono::file_clock", "<chrono>", cxx20}, -#line 526 "../../src/gcc/cp/std-name-hint.gperf" +#line 526 "std-name-hint.gperf" {"disjunction_v", "<type_traits>", cxx17}, -#line 485 "../../src/gcc/cp/std-name-hint.gperf" +#line 485 "std-name-hint.gperf" {"u16string", "<string>", cxx11}, -#line 351 "../../src/gcc/cp/std-name-hint.gperf" +#line 351 "std-name-hint.gperf" {"once_flag", "<mutex>", cxx11}, -#line 491 "../../src/gcc/cp/std-name-hint.gperf" +#line 491 "std-name-hint.gperf" {"string_view", "<string_view>", cxx17}, -#line 304 "../../src/gcc/cp/std-name-hint.gperf" +#line 304 "std-name-hint.gperf" {"allocator_arg", "<memory>", cxx11}, -#line 486 "../../src/gcc/cp/std-name-hint.gperf" +#line 486 "std-name-hint.gperf" {"u32string", "<string>", cxx11}, -#line 213 "../../src/gcc/cp/std-name-hint.gperf" +#line 213 "std-name-hint.gperf" {"unwrap_ref_decay", "<functional>", cxx20}, -#line 70 "../../src/gcc/cp/std-name-hint.gperf" +#line 70 "std-name-hint.gperf" {"chrono::leap_second", "<chrono>", cxx20}, -#line 92 "../../src/gcc/cp/std-name-hint.gperf" +#line 92 "std-name-hint.gperf" {"chrono::utc_clock", "<chrono>", cxx20}, -#line 107 "../../src/gcc/cp/std-name-hint.gperf" +#line 107 "std-name-hint.gperf" {"derived_from", "<concepts>", cxx20}, -#line 99 "../../src/gcc/cp/std-name-hint.gperf" +#line 99 "std-name-hint.gperf" {"strong_ordering", "<compare>", cxx20}, -#line 497 "../../src/gcc/cp/std-name-hint.gperf" +#line 497 "std-name-hint.gperf" {"generic_category", "<system_error>", cxx11}, -#line 125 "../../src/gcc/cp/std-name-hint.gperf" +#line 125 "std-name-hint.gperf" {"totally_ordered", "<concepts>", cxx20}, -#line 494 "../../src/gcc/cp/std-name-hint.gperf" +#line 494 "std-name-hint.gperf" {"error_category", "<system_error>", cxx11}, -#line 82 "../../src/gcc/cp/std-name-hint.gperf" +#line 82 "std-name-hint.gperf" {"chrono::round", "<chrono>", cxx17}, -#line 357 "../../src/gcc/cp/std-name-hint.gperf" +#line 357 "std-name-hint.gperf" {"unique_lock", "<mutex>", cxx11}, -#line 319 "../../src/gcc/cp/std-name-hint.gperf" +#line 319 "std-name-hint.gperf" {"make_shared", "<memory>", cxx11}, -#line 507 "../../src/gcc/cp/std-name-hint.gperf" +#line 507 "std-name-hint.gperf" {"this_thread", "<thread>", cxx11}, -#line 449 "../../src/gcc/cp/std-name-hint.gperf" +#line 449 "std-name-hint.gperf" {"invalid_argument", "<stdexcept>", cxx98}, -#line 354 "../../src/gcc/cp/std-name-hint.gperf" +#line 354 "std-name-hint.gperf" {"scoped_lock", "<mutex>", cxx17}, -#line 268 "../../src/gcc/cp/std-name-hint.gperf" +#line 268 "std-name-hint.gperf" {"wclog", "<iostream>", cxx98}, -#line 506 "../../src/gcc/cp/std-name-hint.gperf" +#line 506 "std-name-hint.gperf" {"jthread", "<thread>", cxx20}, -#line 97 "../../src/gcc/cp/std-name-hint.gperf" +#line 97 "std-name-hint.gperf" {"partial_ordering", "<compare>", cxx20}, -#line 68 "../../src/gcc/cp/std-name-hint.gperf" +#line 68 "std-name-hint.gperf" {"chrono::high_resolution_clock", "<chrono>", cxx11}, -#line 307 "../../src/gcc/cp/std-name-hint.gperf" +#line 307 "std-name-hint.gperf" {"assume_aligned", "<memory>", cxx20}, -#line 488 "../../src/gcc/cp/std-name-hint.gperf" +#line 488 "std-name-hint.gperf" {"wstring", "<string>", cxx98}, -#line 192 "../../src/gcc/cp/std-name-hint.gperf" +#line 192 "std-name-hint.gperf" {"wformat_string", "<format>", cxx20}, -#line 189 "../../src/gcc/cp/std-name-hint.gperf" +#line 189 "std-name-hint.gperf" {"wformat_args", "<format>", cxx20} }; diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 88f8f34..447fe81 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -156,7 +156,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain) { if (complain & tf_error) cxx_incomplete_type_diagnostic (value, type, DK_ERROR); - note_failed_type_completion_for_satisfaction (type); + note_failed_type_completion (type, complain); return NULL_TREE; } else @@ -1372,17 +1372,12 @@ cxx_safe_arg_type_equiv_p (tree t1, tree t2) && TYPE_PTR_P (t2)) return true; - /* The signedness of the parameter matters only when an integral - type smaller than int is promoted to int, otherwise only the - precision of the parameter matters. - This check should make sure that the callee does not see - undefined values in argument registers. */ + /* Only the precision of the parameter matters. This check should + make sure that the callee does not see undefined values in argument + registers. */ if (INTEGRAL_TYPE_P (t1) && INTEGRAL_TYPE_P (t2) - && TYPE_PRECISION (t1) == TYPE_PRECISION (t2) - && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) - || !targetm.calls.promote_prototypes (NULL_TREE) - || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))) + && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) return true; return same_type_p (t1, t2); @@ -2089,7 +2084,14 @@ cxx_sizeof_or_alignof_type (location_t loc, tree type, enum tree_code op, bool dependent_p = dependent_type_p (type); if (!dependent_p) - complete_type (type); + { + complete_type (type); + if (!COMPLETE_TYPE_P (type)) + /* Call this here because the incompleteness diagnostic comes from + c_sizeof_or_alignof_type instead of + complete_type_or_maybe_complain. */ + note_failed_type_completion (type, complain); + } if (dependent_p /* VLA types will have a non-constant size. In the body of an uninstantiated template, we don't need to try to compute the @@ -2111,7 +2113,7 @@ cxx_sizeof_or_alignof_type (location_t loc, tree type, enum tree_code op, return c_sizeof_or_alignof_type (loc, complete_type (type), op == SIZEOF_EXPR, std_alignof, - complain); + complain & (tf_warning_or_error)); } /* Return the size of the type, without producing any warnings for @@ -3999,13 +4001,61 @@ cp_build_array_ref (location_t loc, tree array, tree idx, } case COND_EXPR: - ret = build_conditional_expr - (loc, TREE_OPERAND (array, 0), - cp_build_array_ref (loc, TREE_OPERAND (array, 1), idx, - complain), - cp_build_array_ref (loc, TREE_OPERAND (array, 2), idx, - complain), - complain); + tree op0, op1, op2; + op0 = TREE_OPERAND (array, 0); + op1 = TREE_OPERAND (array, 1); + op2 = TREE_OPERAND (array, 1); + if (TREE_SIDE_EFFECTS (idx) || !tree_invariant_p (idx)) + { + /* If idx could possibly have some SAVE_EXPRs, turning + (op0 ? op1 : op2)[idx] into + op0 ? op1[idx] : op2[idx] can lead into temporaries + initialized in one conditional path and uninitialized + uses of them in the other path. + And if idx is a really large expression, evaluating it + twice is also not optimal. + On the other side, op0 must be sequenced before evaluation + of op1 and op2 and for C++17 op0, op1 and op2 must be + sequenced before idx. + If idx is INTEGER_CST, we can just do the optimization + without any SAVE_EXPRs, if op1 and op2 are both ARRAY_TYPE + VAR_DECLs or COMPONENT_REFs thereof (so their address + is constant or relative to frame), optimize into + (SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0>) + ? op1[SAVE_EXPR <idx>] : op2[SAVE_EXPR <idx>] + Otherwise avoid this optimization. */ + if (flag_strong_eval_order == 2) + { + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) + { + if (!address_invariant_p (op1) || !address_invariant_p (op2)) + { + /* Force default conversion on array if + we can't optimize this and array is ARRAY_TYPE + COND_EXPR, we can't leave COND_EXPRs with + ARRAY_TYPE in the IL. */ + array = cp_default_conversion (array, complain); + if (error_operand_p (array)) + return error_mark_node; + break; + } + } + else if (!POINTER_TYPE_P (TREE_TYPE (array)) + || !tree_invariant_p (op1) + || !tree_invariant_p (op2)) + break; + } + if (TREE_SIDE_EFFECTS (idx)) + { + idx = save_expr (idx); + op0 = save_expr (op0); + tree tem = build_compound_expr (loc, op0, idx); + op0 = build_compound_expr (loc, tem, op0); + } + } + op1 = cp_build_array_ref (loc, op1, idx, complain); + op2 = cp_build_array_ref (loc, op2, idx, complain); + ret = build_conditional_expr (loc, op0, op1, op2, complain); protected_set_expr_location (ret, loc); return ret; @@ -11468,6 +11518,12 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling) && call_from_lambda_thunk_p (retval)) converted = true; + /* Don't check copy-initialization for NRV in a coroutine ramp; we + implement this case as NRV, but it's specified as directly + initializing the return value from get_return_object(). */ + if (DECL_RAMP_P (current_function_decl) && named_return_value_okay_p) + converted = true; + /* First convert the value to the function's return type, then to the type of return value's location to handle the case that functype is smaller than the valtype. */ |