diff options
Diffstat (limited to 'gcc/cp')
41 files changed, 11647 insertions, 2747 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d266ef9..e32ee1c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,2184 @@ +2025-08-29 Sirui Mu <msrlancern@gmail.com> + + * typeck.cc (cp_build_array_ref): Handle 0[arr] earlier. + +2025-08-28 Jason Merrill <jason@redhat.com> + + PR c++/107953 + * parser.cc (cp_parser_lambda_expression): Set + greater_than_is_operator_p. + +2025-08-28 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119844 + * typeck2.cc (cxx_incomplete_type_inform): Add explanation when + a similar type is complete but attached to a different module. + Also fix handling of partial specs and templates. + +2025-08-28 Jakub Jelinek <jakub@redhat.com> + + PR c++/121583 + * semantics.cc (apply_deduced_return_type): Adjust + fun->returns*_struct when !uses_template_parms (fco) instead of + when !processing_template_decl. + +2025-08-28 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/121575 + * pt.cc (tsubst_expr) <case PARM_DECL>: If DECL_CONTEXT (t) isn't a + template return t for PARM_DECLs without local specialization. + +2025-08-26 Sandra Loosemore <sloosemore@baylibre.com> + + PR middle-end/118839 + * decl.cc (omp_declare_variant_finalize_one): Error if variant + is the same as base. + +2025-08-26 Sandra Loosemore <sloosemore@baylibre.com> + + * parser.cc (cp_finish_omp_declare_variant): Structure diagnostic + code similarly to C front end. Make check for a missing "match" + clause unconditional. + +2025-08-25 Jakub Jelinek <jakub@redhat.com> + + * pt.cc (finish_expansion_stmt): Implement C++ CWG3048 + - Empty destructuring expansion statements. Don't error for + destructuring expansion stmts if sz is 0, don't call + fit_decomposition_lang_decl if n is 0 and pass NULL rather than + this_decomp to cp_finish_decl. + +2025-08-25 Jakub Jelinek <jakub@redhat.com> + + PR c++/121601 + * constexpr.cc (cxx_bind_parameters_in_call): Move break + if *jump_target before the check for null this object pointer. + +2025-08-23 Eczbek <eczbek.void@gmail.com> + + PR c++/116928 + * parser.cc (cp_parser_braced_list): Set greater_than_is_operator_p. + +2025-08-23 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120499 + * method.cc (synthesize_method): Set the instantiating module. + +2025-08-21 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * constexpr.cc (cxx_eval_store_expression): Allow clobber of a const + object. + +2025-08-21 Jason Merrill <jason@redhat.com> + + PR c++/120757 + * pt.cc (tsubst_expr) [OFFSET_REF]: Don't tsubst the type. + +2025-08-20 Marek Polacek <polacek@redhat.com> + + PR c++/121553 + * name-lookup.cc (check_local_shadow): Check !is_normal_capture_proxy. + +2025-08-19 Ben Wu <soggysocks206@gmail.com> + + PR c++/120618 + * parser.cc (cp_parser_compound_requirement): Set type to + NULL_TREE for invalid type-constraint. + +2025-08-19 Patrick Palka <ppalka@redhat.com> + + PR c++/121351 + * class.cc (add_method): Use outer_template_args when + substituting outer template arguments into constraints. + +2025-08-19 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120195 + * name-lookup.cc (do_nonmember_using_decl): Also handle change + in exportedness of a function. + +2025-08-18 Indu Bhagat <indu.bhagat@oracle.com> + + * typeck.cc (get_member_function_from_ptrfunc): Use + 'sanitize_code_type' instead of 'unsigned int'. + +2025-08-17 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120503 + PR c++/120824 + * cp-tree.h (TYPE_UNNAMED_P): Adjust for enums with enumerators + for linkage purposes. + (enum_with_enumerator_for_linkage_p): Declare. + * decl.cc (name_unnamed_type): Adjust assertions to handle enums + with enumerators for linkage purposes. + (grokdeclarator): Use a typedef name for enums with enumerators + for linkage purposes. + (enum_with_enumerator_for_linkage_p): New function. + (finish_enum_value_list): Reset type linkage for enums with + enumerators for linkage purposes. + * mangle.cc (write_unnamed_enum_name): New function. + (write_unqualified_name): Handle enums with enumerators for + linkage purposes. + * tree.cc (decl_linkage): Fixup unnamed enums. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + * cp-trait.def (STRUCTURED_BINDING_SIZE): New unary trait. + * cp-tree.h (finish_structured_binding_size): Declare. + * semantics.cc (trait_expr_value): Handle + CPTK_STRUCTURED_BINDING_SIZE. + (finish_structured_binding_size): New function. + (finish_trait_expr): Handle CPTK_RANK and CPTK_TYPE_ORDER + in the switch instead of just doing break; for those and + ifs at the end to handle them. Handle CPTK_STRUCTURED_BINDING_SIZE. + * pt.cc (tsubst_expr): Likewise. + * constraint.cc (diagnose_trait_expr): Likewise. + * decl.cc (get_tuple_size): Use mce_true for maybe_const_value. + (cp_decomp_size): Diagnose incomplete types not just if + processing_template_decl, and use error_at instead of pedwarn. + If btype is NULL, just return 0 instead of diagnosing an error. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + PR c++/121552 + * decl.cc: Implement C++20 P1766R1 - Mitigating minor modules maladies. + (diagnose_non_c_class_typedef_for_linkage, + maybe_diagnose_non_c_class_typedef_for_linkage): New functions. + (name_unnamed_type): Call + maybe_diagnose_non_c_class_typedef_for_linkage. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + PR c++/121539 + * parser.cc (cp_parser_cache_defarg): Set done to true for + CPP_ELLIPSIS followed by CPP_CLOSE_PAREN in !nsdmi at depth 0. + +2025-08-15 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + PR target/121520 + * lex.cc (cxx_init): Remove warn_on lambda. Use cpp_warn instead of + cpp_lookup and NODE_WARN bit setting or warn_on. + +2025-08-14 Jakub Jelinek <jakub@redhat.com> + + PR c++/121524 + * tree.cc (build_cplus_array_type): Don't reuse variant type + if it has TREE_DEPRECATED or TREE_UNAVAILABLE flags set or, + unless elt_type has TYPE_USER_ALIGN set and TYPE_ALIGN is + TYPE_ALIGN of elt_type, TYPE_USER_ALIGN is not set. + +2025-08-13 Marek Polacek <polacek@redhat.com> + + PR c++/102610 + * cp-tree.h (LAMBDA_EXPR_CONST_QUAL_P): Define. + (maybe_add_dummy_lambda_op): Declare. + (remove_dummy_lambda_op): Declare. + (push_capture_proxies): Adjust. + * lambda.cc (build_capture_proxy): No longer static. New early_p + parameter. Use it. + (add_capture): Adjust the call to build_capture_proxy. + (resolvable_dummy_lambda): Check DECL_LAMBDA_FUNCTION_P. + (push_capture_proxies): New. + (start_lambda_function): Use it. + * name-lookup.cc (check_local_shadow): Give an error for + is_capture_proxy. + (cp_binding_level_descriptor): Add lambda-scope. + (begin_scope) <case sk_lambda>: New case. + * name-lookup.h (enum scope_kind): Add sk_lambda. + (struct cp_binding_level): Widen kind. + * parser.cc (cp_parser_lambda_expression): Create a new (lambda) scope + after the lambda-introducer. + (cp_parser_lambda_declarator_opt): Set LAMBDA_EXPR_CONST_QUAL_P. + Create a dummy operator() if needed. Inject the captures into the + lambda scope. Remove the dummy operator(). + (make_dummy_lambda_op): New. + (maybe_add_dummy_lambda_op): New. + (remove_dummy_lambda_op): New. + * pt.cc (tsubst_lambda_expr): Begin/end a lambda scope. Push the + capture proxies. Build/remove a dummy operator() if needed. Set + LAMBDA_EXPR_CONST_QUAL_P. + * semantics.cc (parsing_lambda_declarator): New. + (outer_var_p): Also consider captures as outer variables if in a lambda + declarator. + (process_outer_var_ref): Reset containing_function when + parsing_lambda_declarator. + (finish_decltype_type): Process decls in the lambda-declarator as well. + Look at LAMBDA_EXPR_CONST_QUAL_P unless we have an xobj function. + +2025-08-13 Jakub Jelinek <jakub@redhat.com> + + PR c++/120776 + * cp-tree.def: Implement C++26 P1306R5 - Expansion statements. + (TEMPLATE_FOR_STMT): New tree code. + * cp-tree.h (struct saved_scope): Add expansion_stmt. + (in_expansion_stmt): Define. + (TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY, + TEMPLATE_FOR_SCOPE, TEMPLATE_FOR_INIT_STMT): Define. + (struct tinst_level): Adjust comment. + (cp_decomp_size, finish_expansion_stmt, do_pushlevel, + cp_build_range_for_decls, build_range_temp, + cp_perform_range_for_lookup, begin_template_for_scope): Declare. + (finish_range_for_stmt): Remove declaration. + * cp-objcp-common.cc (cp_common_init_ts): Handle TEMPLATE_FOR_STMT. + * name-lookup.h (enum scope_kind): Add sk_template_for enumerator. + (struct cp_binding_level): Enlarge kind bitfield from 4 to 5 bits. + Adjust comment with remaining space bits. + * name-lookup.cc (check_local_shadow): Handle sk_template_for like + sk_for. + (cp_binding_level_descriptor): Add entry for sk_template_for. + (begin_scope): Handle sk_template_for. + * parser.h (IN_EXPANSION_STMT): Define. + * parser.cc (cp_debug_parser): Print IN_EXPANSION_STMT bit. + (cp_parser_lambda_expression): Temporarily clear in_expansion_stmt. + (cp_parser_statement): Handle RID_TEMPLATE followed by RID_FOR for + C++11. + (cp_parser_label_for_labeled_statement): Complain about named labels + inside of expansion stmt body. + (cp_hide_range_decl): New function. + (cp_parser_range_for): Use it. Adjust do_range_for_auto_deduction + caller. Remove second template argument from auto_vecs bindings and + names. + (build_range_temp): No longer static. + (do_range_for_auto_deduction): Add expansion_stmt argument. + (cp_build_range_for_decls): New function. + (cp_convert_range_for): Use it. Call cp_perform_range_for_lookup + rather than cp_parser_perform_range_for_lookup. + (cp_parser_perform_range_for_lookup): Rename to ... + (cp_perform_range_for_lookup): ... this. No longer static. Add + complain argument and handle it. + (cp_parser_range_for_member_function): Rename to ... + (cp_range_for_member_function): ... this. + (cp_parser_expansion_statement): New function. + (cp_parser_jump_statement): Handle IN_EXPANSION_STMT. + (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction caller. + Call cp_perform_range_for_lookup rather than + cp_parser_perform_range_for_lookup. + * error.cc (print_instantiation_full_context): Handle tldcl being + TEMPLATE_FOR_STMT. + (print_instantiation_partial_context_line): Likewise. + * constexpr.cc (potential_constant_expression_1): Handle + TEMPLATE_FOR_STMT. + * decl.cc (poplevel_named_label_1): Use obl instead of bl->level_chain. + (finish_case_label): Diagnose case labels inside of template for. + (find_decomp_class_base): Add complain argument, don't diagnose + anything and just return error_mark_node if tf_none, adjust recursive + call. + (cp_decomp_size): New function. + (cp_finish_decomp): Adjust find_decomp_class_base caller. + * semantics.cc (do_pushlevel): No longer static. + (begin_template_for_scope): New function. + * pt.cc (push_tinst_level_loc): Handle TEMPLATE_FOR_STMT. + (reopen_tinst_level): Likewise. + (tsubst_stmt): Handle TEMPLATE_FOR_STMT. + (struct expansion_stmt_bc): New type. + (expansion_stmt_find_bc_r, finish_expansion_stmt): New functions. + * decl2.cc (decl_dependent_p): Return true for current function's decl + if in_expansion_stmt. + * call.cc (extend_ref_init_temps): Don't extend_all_temps if + TREE_STATIC (decl). + * cxx-pretty-print.cc (cxx_pretty_printer::statement): Handle + TEMPLATE_FOR_STMT. + +2025-08-13 Benjamin Wu <bwu25@cs.washington.edu> + + * lex.cc (init_operators): Fix typo. + +2025-08-11 Nicolas Werner <nicolas.werner@hotmail.de> + + * mapper-client.cc (spawn_mapper_program): change argv parsing + +2025-08-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/117783 + * decl.cc (set_sb_pack_name): For name independent decls + just clear DECL_NAME instead of appending #i to it. + +2025-08-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/117783 + * decl.cc (cp_finish_decomp): Don't sorry on tuple static + structured bindings with a pack, instead temporarily reset + DECL_NAME of the individual vars in the pack to the name + of the pack for cp_finish_decl time and force mangling. + +2025-08-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/121442 + * parser.cc (cp_parser_decomposition_declaration): Don't copy + DECL_DECLARED_CONST{EXPR,INIT}_P bits from decl to decl2 if + decl is error_mark_node. + +2025-08-08 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cp_adjust_diagnostic_info): Convert "context" arg from + ptr to const &. + +2025-08-07 Patrick Palka <ppalka@redhat.com> + + * call.cc (extract_call_expr): Remove handling of C++20 + rewritten comparison operators. + +2025-08-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/117783 + * parser.cc: Implement C++26 P1061R10 - Structured Bindings can + introduce a Pack. + (cp_parser_range_for): Also handle TREE_VEC as DECL_VALUE_EXPR + instead of ARRAY_REF. + (cp_parser_decomposition_declaration): Use sb-identifier-list instead + of identifier-list in comments. Parse structured bindings with + structured binding pack. Don't emit pedwarn about structured + binding attributes in structured bindings inside of a condition. + (cp_convert_omp_range_for): Also handle TREE_VEC as DECL_VALUE_EXPR + instead of ARRAY_REF. + * decl.cc (get_tuple_element_type): Change i argument type from + unsigned to unsigned HOST_WIDE_INT. + (get_tuple_decomp_init): Likewise. + (set_sb_pack_name): New function. + (cp_finish_decomp): Handle structured binding packs. + * pt.cc (tsubst_pack_expansion): Handle structured binding packs + and capture proxies for them. Formatting fixes. + (tsubst_decl): For structured binding packs don't tsubst TREE_TYPE + first, instead recreate the type after r is created. + (tsubst_omp_for_iterator): Also handle TREE_VEC as DECL_VALUE_EXPR + instead of ARRAY_REF. + (tsubst_expr): Handle sizeof... on non-dependent structure binding + packs. + (value_dependent_expression_p): Return false for sizeof... on + non-dependent structure binding packs. + (instantiation_dependent_r): Don't recurse on sizeof... on + non-dependent structure binding packs. + * constexpr.cc (potential_constant_expression_1): Also handle + TREE_VEC on DECL_VALUE_EXPR of structure binding packs. + +2025-08-07 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * lex.cc (cxx_init): Mark cpp nodes corresponding + to keywords, identifiers with special meaning and standard + attribute identifiers as NODE_WARN if warn_keyword_macro. + +2025-08-06 Patrick Palka <ppalka@redhat.com> + + PR c++/121231 + PR c++/119688 + PR c++/94511 + * mangle.cc (write_expression): Write out implicit non-trailing + zeroes of a CONSTRUCTOR when the ABI version is at least 21. + +2025-08-06 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_indirect_ref): Improve diagnostic. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * parser.cc (cp_parser_omp_clause_from_to): Parse 'iterator' modifier. + * semantics.cc (finish_omp_clauses): Finish iterators for to/from + clauses. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * parser.cc (cp_parser_omp_clause_map): Parse 'iterator' modifier. + * semantics.cc (finish_omp_clauses): Finish iterators. Apply + iterators to generated clauses. + +2025-08-05 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * constexpr.cc (cxx_eval_store_expression): Handle clobbers. + (potential_constant_expression_1): Handle clobbers more. + * decl.cc (build_clobber_this): Use INIT_EXPR for initial clobber. + * init.cc (build_new_1): Clobber on placement new. + (build_vec_init): Don't clean up after clobber. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/121351 + PR c++/119859 + * class.cc (add_method): Substitute outer template arguments + into constraints before comparing them if the declarations are + from different classes. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/120620 + * constexpr.cc (cxx_dynamic_cast_fn_p): Return true only + for synthesized __dynamic_cast. + +2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/108080 + * module.cc (trees_out::core_vals): Warn when streaming + target/optimize node; adjust comments. + (trees_in::core_vals): Don't stream a target/optimize node. + +2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/121238 + * module.cc (trees_in::fn_parms_fini): Merge properties for + definitions. + +2025-07-31 Jason Merrill <jason@redhat.com> + + PR c++/120800 + * constexpr.cc (cxx_eval_vec_init_1): Suppress access control. + +2025-07-31 Marek Polacek <polacek@redhat.com> + + PR c++/120775 + * constexpr.cc (cxx_eval_outermost_constant_expr): Use + extract_call_expr. + * cp-tree.h (CONSTEVAL_BLOCK_P, LAMBDA_EXPR_CONSTEVAL_BLOCK_P): Define. + (finish_static_assert): Adjust declaration. + (current_nonlambda_function): Likewise. + * lambda.cc (current_nonlambda_function): New parameter. Only keep + iterating if the function represents a consteval block. + * parser.cc (cp_parser_lambda_expression): New parameter for + consteval blocks. Use it. Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P. + (cp_parser_lambda_declarator_opt): Likewise. + (build_empty_string): New. + (cp_parser_next_tokens_are_consteval_block_p): New. + (cp_parser_consteval_block): New. + (cp_parser_block_declaration): Handle consteval blocks. + (cp_parser_static_assert): Use build_empty_string. + (cp_parser_member_declaration): Handle consteval blocks. + * pt.cc (tsubst_stmt): Adjust a call to finish_static_assert. + * semantics.cc (finish_fname): Warn for consteval blocks. + (finish_static_assert): New parameter for consteval blocks. Set + CONSTEVAL_BLOCK_P. Evaluate consteval blocks specially. + +2025-07-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/121291 + * constraint.cc (diagnose_trait_expr): Remove assumption about + failures returning error_mark_node. + * except.cc (explain_not_noexcept): Allow expr not being + noexcept. + * method.cc (build_invoke): Adjust comment. + (is_trivially_xible): Always note non-trivial components if expr + is not null or error_mark_node. + (is_nothrow_xible): Likewise for non-noexcept components. + (is_nothrow_convertible): Likewise. + +2025-07-30 Jason Merrill <jason@redhat.com> + + * pt.cc (convert_nontype_argument_function): Check + cxx_constant_value on failure. + (invalid_tparm_referent_p): Likewise. + +2025-07-30 Jakub Jelinek <jakub@redhat.com> + + PR c++/121133 + * parser.cc (cp_parser_unary_expression): Adjust + cp_parser_extension_opt caller and restore warn_long_long. + (cp_parser_declaration): Likewise. + (cp_parser_block_declaration): Likewise. + (cp_parser_member_declaration): Likewise. + (cp_parser_extension_opt): Add SAVED_LONG_LONG argument, + save previous warn_long_long state into it and clear it + for __extension__. + +2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com> + + * cp-tree.h (struct lang_type): Add comment mentioning modules. + * module.cc (trees_out::lang_type_bools): Stream new flags, use + gcc_checking_assert. + (trees_in::lang_type_bools): Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * constexpr.cc: Update usage of "diagnostic_info" to explicitly + refer to "diagnostics::diagnostic_info". + * cp-tree.h: Likewise. + * error.cc: Likewise. + * module.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * call.cc: Update for diagnostic_t becoming + enum class diagnostics::kind. + * constexpr.cc: Likewise. + * cp-tree.h: Likewise. + * decl.cc: Likewise. + * error.cc: Likewise. + * init.cc: Likewise. + * method.cc: Likewise. + * module.cc: Likewise. + * parser.cc: Likewise. + * pt.cc: Likewise. + * semantics.cc: Likewise. + * typeck.cc: Likewise. + * typeck2.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for renaming of diagnostic_option_id to + diagnostics::option_id. + * decl.cc: Likewise. + * error.cc: Likewise. + * name-lookup.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * error.cc: Update for move of diagnostic-color.h to + diagnostics/color.h. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for diagnostic_context becoming + diagnostics::context. + * error.cc: Likewise. + * module.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * constexpr.cc: Update to add "m_" prefix to fields of + diagnostic_info throughout. + * error.cc: Likewise. + +2025-07-25 David Malcolm <dmalcolm@redhat.com> + + * cp-tree.h: Update for move of diagnostics output formats into + namespace "diagnostics" as "sinks". + * error.cc: Likewise. + +2025-07-25 Patrick Palka <ppalka@redhat.com> + + * call.cc (build_new_op): If the selected candidate is + rewritten, communicate the LOOKUP_REWRITTEN/REVERSED flags to + the caller via the 'overload' out-parameter, and stop clearing + '*overload' in that case. + * tree.cc (build_min_non_dep_op_overload): Handle rebuilding all + C++20 rewritten comparison operator expressions. + +2025-07-25 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/121219 + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Reorder the return + expressions for the 'normal' and 'allocation failed' cases so that + NRV constraints are met. + +2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/117294 + PR c++/113854 + * call.cc (implicit_conversion_error): Hide label when printing + a stub object. + (convert_like_internal): Likewise, and nest candidate + diagnostics. + * constexpr.cc (diagnose_failing_condition): Nest diagnostics, + attempt to provide more helpful diagnostics for traits. + * constraint.cc (satisfy_atom): Pass result before constant + evaluation to diagnose_atomic_constraint. + (diagnose_trait_expr): Adjust diagnostics for clarity and + detail. + (maybe_diagnose_standard_trait): New function. + (diagnose_atomic_constraint): Attempt to provide more helpful + diagnostics for more traits. + * cp-tree.h (explain_not_noexcept): Declare new function. + (is_trivially_xible): Add parameter. + (is_nothrow_xible): Likewise. + (is_xible): Likewise. + (is_convertible): Likewise. + (is_nothrow_convertible): Likewise. + (diagnose_trait_expr): Declare new function. + (maybe_diagnose_standard_trait): Declare new function. + * error.cc (dump_type) <case TREE_VEC>: Handle trait types. + * except.cc (explain_not_noexcept): New function. + * method.cc (build_trait_object): Add complain parameter. + (build_invoke): Propagate complain parameter. + (assignable_expr): Add explain parameter to show diagnostics. + (constructible_expr): Likewise. + (destructible_expr): Likewise. + (is_xible_helper): Replace trivial flag with explain flag, + add diagnostics. + (is_trivially_xible): New explain flag. + (is_nothrow_xible): Likewise. + (is_xible): Likewise. + (is_convertible_helper): Add complain flag. + (is_convertible): New explain flag. + (is_nothrow_convertible): Likewise. + * typeck.cc (cp_build_function_call_vec): Add handling for stub + objects. + (convert_arguments): Always return -1 on error. + * typeck2.cc (cxx_readonly_error): Add handling for stub + objects. + +2025-07-24 Jason Merrill <jason@redhat.com> + + * pt.cc (tsubst_lambda_expr): Revert r9-5971 change. + +2025-07-24 Jason Merrill <jason@redhat.com> + + PR c++/114632 + PR c++/101233 + * lambda.cc (maybe_add_lambda_conv_op): Not for xobj lambda. + * pt.cc (tsubst_function_decl): Add cp_evaluated. + (alias_ctad_tweaks): Revert PR101233 fix. + +2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120412 + * module.cc (trees_out::core_vals): Write TU_LOCAL_ENTITY bits. + (trees_in::core_vals): Read it. + (trees_in::tree_node): Handle TU_LOCAL_ENTITY typedefs. + +2025-07-23 Patrick Palka <ppalka@redhat.com> + + PR c++/121179 + * call.cc (build_new_op): Don't clear *overload for a simple + != to == rewrite. + * tree.cc (build_min_non_dep_op_overload): Handle TRUTH_NOT_EXPR + appearing in a rewritten operator expression. + +2025-07-23 Patrick Palka <ppalka@redhat.com> + + PR c++/121055 + * method.cc (build_invoke): Correct reference_wrapper handling. + +2025-07-22 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs + when activating an array member of a union. + +2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> + + * semantics.cc (finish_asm_stmt): Pass null pointer to + parse_{input,output}_constraint(). + +2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * pt.cc (tsubst_omp_clause_decl): Use OMP_ITERATOR_DECL_P. + * semantics.cc (handle_omp_array_sections): Likewise. + (finish_omp_clauses): Likewise. + +2025-07-16 Alfie Richards <alfie.richards@arm.com> + + * class.cc (add_method): Remove argument. + * cp-tree.h (maybe_version_functions): Ditto. + * decl.cc (decls_match): Ditto. + (maybe_version_functions): Ditto. + +2025-07-16 Jeremy Rifkin <jeremy@rifkin.dev> + + PR c/82134 + * call.cc (build_call_a): Add suppress_warning + * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning + +2025-07-15 Jason Merrill <jason@redhat.com> + + PR c++/44677 + * cp-gimplify.cc (cp_fold) [CLEANUP_POINT_EXPR]: Don't force rvalue. + [COMPOUND_EXPR]: Likewise. + * cvt.cc (convert_to_void): Call mark_exp_read later. + * expr.cc (mark_use): Turn off read_p for any void argument. + (mark_exp_read): Return early for void argument. + +2025-07-15 Jason Merrill <jason@redhat.com> + + PR c++/120577 + * constexpr.cc (cxx_eval_call_expression): Set + CONSTRUCTOR_NO_CLEARING on initial value for ctor. + (cxx_eval_component_reference): Make value-initialization + of an aggregate member explicit. + +2025-07-15 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c/44677 + * cp-gimplify.cc (cp_fold): Clear DECL_READ_P on lhs of MODIFY_EXPR + after cp_fold_rvalue if it wasn't set before. + * decl.cc (poplevel): Use OPT_Wunused_but_set_variable_ + instead of OPT_Wunused_but_set_variable. + (finish_function): Use OPT_Wunused_but_set_parameter_ + instead of OPT_Wunused_but_set_parameter. + * expr.cc (mark_use): Clear read_p for {PRE,POST}{IN,DE}CREMENT_EXPR + cast to void on {VAR,PARM}_DECL for + -Wunused-but-set-{parameter,variable}={2,3}. + (mark_exp_read): Handle {PRE,POST}{IN,DE}CREMENT_EXPR and don't handle + it when cast to void. + * module.cc (trees_in::fn_parms_fini): Remove unused but set variable + ix. + * semantics.cc (finish_unary_op_expr): Return early for + PRE{IN,DE}CREMENT_EXPR. + * typeck.cc (cp_build_unary_op): Clear DECL_READ_P + after mark_lvalue_use for -Wunused-but-set-{parameter,variable}={2,3} + on PRE{IN,DE}CREMENT_EXPR argument. + (cp_build_modify_expr): Clear DECL_READ_P after cp_build_binary_op + for -Wunused-but-set-{parameter,variable}=3. + +2025-07-11 Jakub Jelinek <jakub@redhat.com> + + PR c++/119064 + * cp-tree.h: Implement C++26 P2786R13 - Trivial Relocatability. + (struct lang_type): Add trivially_relocatable, + trivially_relocatable_computed, replaceable and replaceable_computed + bitfields. Change width of dummy from 2 to 30. + (CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT, + CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, CLASSTYPE_REPLACEABLE_BIT, + CLASSTYPE_REPLACEABLE_COMPUTED): Define. + (enum virt_specifier): Add VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE + and VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE enumerators. + (trivially_relocatable_type_p, replaceable_type_p): Declare. + * cp-trait.def (IS_NOTHROW_RELOCATABLE, IS_REPLACEABLE, + IS_TRIVIALLY_RELOCATABLE): New traits. + * parser.cc (cp_parser_class_property_specifier_seq_opt): Handle + trivially_relocatable_if_eligible, + __trivially_relocatable_if_eligible, replaceable_if_eligible and + __replaceable_if_eligible. + (cp_parser_class_head): Set CLASSTYPE_REPLACEABLE_BIT + and/or CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT if corresponding + conditional keywords were parsed and assert corresponding *_COMPUTED + macro is false. + * pt.cc (instantiate_class_template): Copy over also + CLASSTYPE_TRIVIALLY_RELOCATABLE_{BIT,COMPUTED} and + CLASSTYPE_REPLACEABLE_{BIT,COMPUTED} bits. + * semantics.cc (referenceable_type_p): Move definition earlier. + (trait_expr_value): Handle CPTK_IS_NOTHROW_RELOCATABLE, + CPTK_IS_REPLACEABLE and CPTK_IS_TRIVIALLY_RELOCATABLE. + (finish_trait_expr): Likewise. + * tree.cc (default_movable_type_p): New function. + (union_with_no_declared_special_member_fns): Likewise. + (trivially_relocatable_type_p): Likewise. + (replaceable_type_p): Likewise. + * constraint.cc (diagnose_trait_expr): Handle + CPTK_IS_NOTHROW_RELOCATABLE, CPTK_IS_REPLACEABLE and + CPTK_IS_TRIVIALLY_RELOCATABLE. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (struct lang_type): Add comment before key_method. + Remove lambda_expr. + (CLASSTYPE_KEY_METHOD): Give NULL_TREE if not TYPE_POLYMORPHIC_P. + (SET_CLASSTYPE_KEY_METHOD): Define. + (CLASSTYPE_LAMBDA_EXPR): Give NULL_TREE if TYPE_POLYMORPHIC_P. + Use key_method member instead of lambda_expr. + (SET_CLASSTYPE_LAMBDA_EXPR): Define. + * class.cc (determine_key_method): Use SET_CLASSTYPE_KEY_METHOD + macro. + * decl.cc (xref_tag): Use SET_CLASSTYPE_LAMBDA_EXPR macro. + * lambda.cc (begin_lambda_type): Likewise. + * module.cc (trees_in::read_class_def): Use SET_CLASSTYPE_LAMBDA_EXPR + and SET_CLASSTYPE_KEY_METHOD macros, assert lambda is NULL if + TYPE_POLYMORPHIC_P and otherwise assert key_method is NULL. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120628 + * parser.cc (cp_parser_elaborated_type_specifier): Use + cp_parser_nth_token_starts_class_definition_p with extra argument 1 + instead of cp_parser_next_token_starts_class_definition_p. + (cp_parser_class_property_specifier_seq_opt): For final conditional + keyword in C++98 check if the token after it isn't + cp_parser_nth_token_starts_class_definition_p nor CPP_NAME and in + that case break without consuming it nor warning. + (cp_parser_class_head): Use + cp_parser_nth_token_starts_class_definition_p with extra argument 1 + instead of cp_parser_next_token_starts_class_definition_p. + (cp_parser_next_token_starts_class_definition_p): Renamed to ... + (cp_parser_nth_token_starts_class_definition_p): ... this. Add N + argument. Use cp_lexer_peek_nth_token instead of cp_lexer_peek_token. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/120569 + * parser.cc (cp_parser_class_property_specifier_seq_opt): New + function. + (cp_parser_class_head): Use it instead of + cp_parser_property_specifier_seq_opt. Don't diagnose + VIRT_SPEC_OVERRIDE here. Formatting fix. + +2025-07-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/117785 + * constexpr.cc: Implement C++26 P3068R5 - constexpr exceptions. + (class constexpr_global_ctx): Add caught_exceptions and + uncaught_exceptions members. + (constexpr_global_ctx::constexpr_global_ctx): Initialize + uncaught_exceptions. + (returns, breaks, continues, switches): Move earlier. + (throws): New function. + (exception_what_str, diagnose_std_terminate, + diagnose_uncaught_exception): New functions. + (enum cxa_builtin): New type. + (cxx_cxa_builtin_fn_p, cxx_eval_cxa_builtin_fn): New functions. + (cxx_eval_builtin_function_call): Add jump_target argument. Call + cxx_eval_cxa_builtin_fn for __builtin_eh_ptr_adjust_ref. Adjust + cxx_eval_constant_expression calls, if it results in jmp_target, + set *jump_target to it and return. + (cxx_bind_parameters_in_call): Add jump_target argument. Pass + it through to cxx_eval_constant_expression. If it sets *jump_target, + break. + (fold_operand): Adjust cxx_eval_constant_expression caller. + (cxx_eval_assert): Likewise. If it set jmp_target, return true. + (cxx_eval_internal_function): Add jump_target argument. Pass it + through to cxx_eval_constant_expression. Return early if *jump_target + after recursing on args. + (cxx_eval_dynamic_cast_fn): Likewise. Don't set reference_p for + C++26 with -fexceptions. + (cxx_eval_thunk_call): Add jump_target argument. Pass it through + to cxx_eval_constant_expression. + (cxx_set_object_constness): Likewise. Don't set TREE_READONLY if + throws (jump_target). + (cxx_eval_call_expression): Add jump_target argument. Pass it + through to cxx_eval_internal_function, cxx_eval_builtin_function_call, + cxx_eval_thunk_call, cxx_eval_dynamic_cast_fn and + cxx_set_object_constness. Pass it through also + cxx_eval_constant_expression on arguments, cxx_bind_parameters_in_call + and cxx_fold_indirect_ref and for those cases return early + if *jump_target. Call cxx_eval_cxa_builtin_fn for cxx_cxa_builtin_fn_p + functions. For cxx_eval_constant_expression on body, pass address of + cleared jmp_target automatic variable, if it throws propagate + to *jump_target and make it non-cacheable. For C++26 don't diagnose + calls to non-constexpr functions before cxx_bind_parameters_in_call + could report some argument throwing an exception. + (cxx_eval_unary_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and return early + if *jump_target after the call. + (cxx_fold_pointer_plus_expression): Likewise. + (cxx_eval_binary_expression): Likewise and similarly for + cxx_fold_pointer_plus_expression call. + (cxx_eval_conditional_expression): Pass jump_target to + cxx_eval_constant_expression on first operand and return early + if *jump_target after the call. + (cxx_eval_vector_conditional_expression): Add jump_target argument. + Pass it through to cxx_eval_constant_expression for all 3 arguments + and return early if *jump_target after any of those calls. + (get_array_or_vector_nelts): Add jump_target argument. Pass it + through to cxx_eval_constant_expression. + (eval_and_check_array_index): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + each of them if *jump_target. + (cxx_eval_array_reference): Likewise. + (cxx_eval_component_reference): Likewise. + (cxx_eval_bit_field_ref): Likewise. + (cxx_eval_bit_cast): Likewise. Assert CHECKING_P call doesn't + throw or return. + (cxx_eval_logical_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + each of them if *jump_target. + (cxx_eval_bare_aggregate): Likewise. + (cxx_eval_vec_init_1): Add jump_target argument. Pass it through + to cxx_eval_bare_aggregate and recursive call. Pass it through + to get_array_or_vector_nelts and cxx_eval_constant_expression + and return early after it if *jump_target. + (cxx_eval_vec_init): Add jump_target argument. Pass it through + to cxx_eval_constant_expression and cxx_eval_vec_init_1. + (cxx_union_active_member): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and return early after it + if *jump_target. + (cxx_fold_indirect_ref_1): Add jump_target argument. Pass it + through to cxx_union_active_member and recursive calls. + (cxx_eval_indirect_ref): Add jump_target argument. Pass it through + to cxx_fold_indirect_ref_1 calls and to recursive call, in which + case return early after it if *jump_target. + (cxx_fold_indirect_ref): Add jump_target argument. Pass it through + to cxx_fold_indirect_ref and cxx_eval_constant_expression calls and + return early after those if *jump_target. + (cxx_eval_trinary_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + those if *jump_target. + (cxx_eval_store_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression and eval_and_check_array_index + calls and return early after those if *jump_target. + (cxx_eval_increment_expression): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls and return early after + those if *jump_target. + (label_matches): Handle VAR_DECL case. + (cxx_eval_statement_list): Remove local_target variable and + !jump_target handling. Handle throws (jump_target) like returns or + breaks. + (cxx_eval_loop_expr): Remove local_target variable and !jump_target + handling. Pass it through to cxx_eval_constant_expression. Handle + throws (jump_target) like returns. + (cxx_eval_switch_expr): Pass jump_target through to + cxx_eval_constant_expression on cond, return early after it + if *jump_target. + (build_new_constexpr_heap_type): Add jump_target argument. Pass it + through to cxx_eval_constant_expression calls, return early after + those if *jump_target. + (merge_jump_target): New function. + (cxx_eval_constant_expression): Make jump_target argument no longer + defaulted, don't test jump_target for NULL. Pass jump_target + through to recursive calls, cxx_eval_call_expression, + cxx_eval_store_expression, cxx_eval_indirect_ref, + cxx_eval_unary_expression, cxx_eval_binary_expression, + cxx_eval_logical_expression, cxx_eval_array_reference, + cxx_eval_component_reference, cxx_eval_bit_field_ref, + cxx_eval_vector_conditional_expression, cxx_eval_bare_aggregate, + cxx_eval_vec_init, cxx_eval_trinary_expression, cxx_fold_indirect_ref, + build_new_constexpr_heap_type, cxx_eval_increment_expression, + cxx_eval_bit_cast and return earlyu after some of those + if *jump_target as needed. + (cxx_eval_constant_expression) <case TARGET_EXPR>: For C++26 push + also CLEANUP_EH_ONLY cleanups, with NULL_TREE marker after them. + (cxx_eval_constant_expression) <case RETURN_EXPR>: Don't + override *jump_target if throws (jump_target). + (cxx_eval_constant_expression) <case TRY_CATCH_EXPR, case TRY_BLOCK, + case MUST_NOT_THROW_EXPR, case TRY_FINALLY_EXPR, case CLEANUP_STMT>: + Handle C++26 constant expressions. + (cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR>: For C++26 + with throws (jump_target) evaluate the CLEANUP_EH_ONLY cleanups as + well, and if not throws (jump_target) skip those. Set *jump_target + if some of the cleanups threw. + (cxx_eval_constant_expression) <case THROW_EXPR>: Recurse on operand + for C++26. + (cxx_eval_outermost_constant_expr): Diagnose uncaught exceptions both + from main expression and cleanups, diagnose also + break/continue/returns from the main expression. Handle + CLEANUP_EH_ONLY cleanup markers. Don't diagnose mutable poison stuff + if non_constant_p. Use different diagnostics for non-deleted heap + allocations if they were allocated by __cxa_allocate_exception. + (callee_might_throw): New function. + (struct check_for_return_continue_data): Add could_throw field. + (check_for_return_continue): Handle AGGR_INIT_EXPR and CALL_EXPR and + set d->could_throw if they could throw. + (potential_constant_expression_1): For CALL_EXPR allow + cxx_dynamic_cast_fn_p calls. For C++26 set *jump_target to void_node + for calls that could throw. For C++26 if call to non-constexpr call + is seen, try to evaluate arguments first and if they could throw, + don't diagnose call to non-constexpr function nor return false. + Adjust check_for_return_continue_data initializers and + set *jump_target to void_node if data.could_throw_p. For C++26 + recurse on THROW_EXPR argument. Add comment explaining TRY_BLOCK + handling with C++26 exceptions. Handle throws like returns in some + cases. + * cp-tree.h (MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P, + MUST_NOT_THROW_CATCH_P, DECL_EXCEPTION_REFCOUNT): Define. + (DECL_LOCAL_DECL_P): Fix comment typo, VARIABLE_DECL -> VAR_DECL. + (enum cp_built_in_function): Add CP_BUILT_IN_EH_PTR_ADJUST_REF, + (handler_match_for_exception_type): Declare. + * call.cc (handler_match_for_exception_type): New function. + * except.cc (initialize_handler_parm): Set MUST_NOT_THROW_CATCH_P + on newly created MUST_NOT_THROW_EXPR. + (begin_eh_spec_block): Set MUST_NOT_THROW_NOEXCEPT_P. + (wrap_cleanups_r): Set MUST_NOT_THROW_THROW_P. + (build_throw): Add another TARGET_EXPR whose scope spans + until after the __cxa_throw call and copy pointer value from ptr + to it and use it in __cxa_throw argument. + * tree.cc (builtin_valid_in_constant_expr_p): Handle + CP_BUILT_IN_EH_PTR_ADJUST_REF. + * decl.cc (cxx_init_decl_processing): Initialize + __builtin_eh_ptr_adjust_ref FE builtin. + * pt.cc (tsubst_stmt) <case MUST_NOT_THROW_EXPR>: Copy the + MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P and + MUST_NOT_THROW_CATCH_P flags. + * cp-gimplify.cc (cp_gimplify_expr) <case CALL_EXPR>: Error on + non-folded CP_BUILT_IN_EH_PTR_ADJUST_REF calls. + +2025-07-09 Jason Merrill <jason@redhat.com> + + PR c++/121012 + PR c++/120917 + * parser.cc (cp_parser_lambda_expression): Clear + parser->in_template_argument_list_p. + +2025-07-09 Jason Merrill <jason@redhat.com> + + PR c++/121008 + PR c++/113563 + * semantics.cc (finish_this_expr): Do check current_class_ref for + non-lambda. + +2025-07-09 Marek Polacek <polacek@redhat.com> + + PR c++/119838 + * parser.cc (cp_parser_nested_name_specifier_opt): New global_p + parameter. Look for "template" when global_p is true. + (cp_parser_simple_type_specifier): Pass global_p to + cp_parser_nested_name_specifier_opt. + +2025-07-08 Marek Polacek <polacek@redhat.com> + Andrew Pinski <quic_apinski@quicinc.com> + + PR c++/83469 + PR c++/93809 + * cp-tree.h (UNION_TYPE_P): Define. + (TYPENAME_IS_UNION_P): Define. + * decl.cc (struct typename_info): Add union_p field. + (struct typename_hasher::equal): Compare union_p field. + (build_typename_type): Use ti.union_p for union_type. Set + TYPENAME_IS_UNION_P. + * error.cc (dump_type) <case TYPENAME_TYPE>: Handle + TYPENAME_IS_UNION_P. + * module.cc (trees_out::type_node): Likewise. + * parser.cc (cp_parser_check_class_key): Allow typename key for union + types and allow union keyword for typename types. + * pt.cc (tsubst) <case TYPENAME_TYPE>: Don't conflate unions with + class_type. For TYPENAME_IS_CLASS_P, check NON_UNION_CLASS_TYPE_P + rather than CLASS_TYPE_P. Add TYPENAME_IS_UNION_P handling. + +2025-07-08 Jakub Jelinek <jakub@redhat.com> + + PR c++/117784 + * decl.cc: Implement part of C++26 P2686R4 - constexpr structured + bindings. + (cp_finish_decl): Pedwarn for C++23 and older on constinit on + structured bindings except for static/thread_local where it uses + earlier error. + (grokdeclarator): Pedwarn on constexpr structured bindings for + C++23 and older instead of emitting error always, don't clear + constexpr_p in that case. + * parser.cc (cp_parser_decomposition_declaration): Copy over + DECL_DECLARED_CONSTEXPR_P and DECL_DECLARED_CONSTINIT_P flags. + +2025-07-07 Alfie Richards <alfie.richards@arm.com> + + PR c++/119498 + * decl.cc (duplicate_decls): Change logic to not always exclude FMV + annotated functions in cases of return type non-ambiguation. + +2025-07-07 Jason Merrill <jason@redhat.com> + + PR c++/120917 + * parser.cc (cp_parser_simple_type_specifier): Attach + auto in targ in parameter to -Wabbreviated-auto-in-template-arg. + (cp_parser_placeholder_type_specifier): Diagnose constrained auto in + template arg. + +2025-07-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/84009 + * parser.cc (cp_parser_decomposition_declaration): Pedwarn + on thread_local, __thread or static in decl_specifiers for + for-range-declaration. + (cp_parser_init_declarator): Likewise, and also for extern + or register. + +2025-07-04 Jason Merrill <jason@redhat.com> + + PR c++/120575 + PR c++/116064 + * parser.cc (cp_parser_abort_tentative_parse): Check seen_error + instead of errorcount. + +2025-07-03 Jason Merrill <jason@redhat.com> + + PR c++/120716 + * lambda.cc (finish_lambda_function): Pass cur_stmt_list to + prune_lambda_captures. + +2025-07-03 Jason Merrill <jason@redhat.com> + + PR c++/120748 + * lambda.cc (lambda_expr_this_capture): Don't return a FIELD_DECL. + * parser.cc (cp_parser_primary_expression): Ignore THIS_FORBIDDEN + if cp_unevaluated_operand. + +2025-07-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/120940 + * typeck.cc (cp_build_array_ref): Fix a pasto. + +2025-07-03 Jason Merrill <jason@redhat.com> + + PR c++/120684 + PR c++/118856 + * constexpr.cc (cxx_eval_constant_expression) [TARGET_EXPR]: Clear + the value first if is_complex. + +2025-07-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/120471 + * typeck.cc (cp_build_array_ref) <case COND_EXPR>: If idx is not + INTEGER_CST, don't optimize the case (but cp_default_conversion on + array early if it has ARRAY_TYPE) or use + SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0> as new op0 depending + on flag_strong_eval_order and whether op1 and op2 are arrays with + invariant address or tree invariant pointers. Formatting fixes. + +2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_out::walking_bit_field_unit): New flag. + (trees_out::trees_out): Initialize it. + (trees_out::core_vals): Set it. + (trees_out::get_merge_kind): Use it, move previous ad-hoc check + into assertion. + +2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120644 + * decl.cc (cp_finish_decl): Also propagate type to partial + templates. + * module.cc (trees_out::decl_value): Add assertion that the + TREE_TYPE of a streamed template decl matches its inner. + (trees_in::is_matching_decl): Clarify function return type + deduction should only occur for non-TEMPLATE_DECL. + * pt.cc (template_for_substitution): Handle partial specs. + +2025-06-27 Marek Polacek <polacek@redhat.com> + + PR c++/120756 + * pt.cc (resolve_nondeduced_context): Pass complain to mark_used. + +2025-06-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/120777 + * constexpr.cc: Implement C++26 P3533R2 - constexpr virtual + inheritance. + (is_valid_constexpr_fn): Don't reject constexpr cdtors in classes + with virtual bases for C++26, adjust error wording. + (cxx_bind_parameters_in_call): Add ORIG_FUN argument, add + values for __in_chrg and __vtt_parm arguments when needed. + (cxx_eval_dynamic_cast_fn): Adjust function comment, HINT -1 + should be possible. For C++26 if obj is cast from POINTER_PLUS_EXPR, + attempt to use cxx_fold_indirect_ref to simplify it and if successful, + build ADDR_EXPR of that. + (cxx_eval_call_expression): Add orig_fun variable, set it to + fun before looking through clones, pass it to + cxx_bind_parameters_in_call. + (reduced_constant_expression_p): Add SZ argument, pass DECL_SIZE + of FIELD_DECL e.index to recursive calls and don't return false + if SZ is non-NULL and there are unfilled fields with bit position + at or above SZ. + (cxx_fold_indirect_ref_1): Handle reading of vtables using + ptrdiff_t dynamic type instead of some pointer type. Set el_sz + to DECL_SIZE_UNIT value rather than TYPE_SIZE_UNIT of + DECL_FIELD_IS_BASE fields in classes with virtual bases. + (cxx_fold_indirect_ref): In canonicalize_obj_off lambda look + through COMPONENT_REFs with DECL_FIELD_IS_BASE in classes with + virtual bases and adjust off correspondingly. Remove assertion that + off is integer_zerop, pass tree_to_uhwi (off) instead of 0 to the + cxx_fold_indirect_ref_1 call. + * cp-tree.h (publicly_virtually_derived_p): Declare. + (reduced_constant_expression_p): Add another tree argument defaulted + to NULL_TREE. + * method.cc (synthesized_method_walk): Don't clear *constexpr_p + if there are virtual bases for C++26. + * class.cc (build_base_path): Compute fixed_type_p and + virtual_access before checks for build_simple_base_path instead of + after that and conditional cp_build_addr_expr. Use build_simple_path + if !virtual_access even when v_binfo is non-NULL. + (layout_virtual_bases): For build_base_field calls use + access_public_node rather than access_private_node if + publicly_virtually_derived_p. + (build_vtbl_initializer): Revert 2018-09-18 and 2018-12-11 changes. + (publicly_virtually_derived_p): New function. + +2025-06-27 Jason Merrill <jason@redhat.com> + + * class.cc (fixed_type_or_null): Handle class-type CALL_EXPR. + * parser.cc (cp_parser_binary_expression): Fix decltype_p handling. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/98735 + PR c++/118904 + * cp-gimplify.cc (source_location_id): Remove. + (fold_builtin_source_location): Use generate_internal_label. + * module.cc (enum tree_tag): Add 'tt_internal_id' enumerator. + (trees_out::tree_value): Adjust assertion, write definitions + of uncontexted VAR_DECLs. + (trees_in::tree_value): Read variable definitions. + (trees_out::tree_node): Write internal labels, adjust assert. + (trees_in::tree_node): Read internal labels. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120040 + * constexpr.cc (cxx_eval_constant_expression): Handle TYPE_NAME + now being a TYPE_DECL rather than just an IDENTIFIER_NODE. + * init.cc (build_new_constexpr_heap_type): Build a TYPE_DECL for + the returned type; mark the type as artificial. + * module.cc (trees_out::type_node): Add some assertions. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/98735 + PR c++/120040 + * module.cc (trees_out::tree_value): Write TYPE_DECLs. + (trees_in::tree_value): Read TYPE_DECLs. + (trees_out::tree_node): Support uncontexted TYPE_DECLs, and + ensure that all parts of a by-value decl are marked for + streaming. + (trees_out::get_merge_kind): Treat members of uncontexted types + as always unique. + +2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com> + + * decl.cc (grokfndecl): Add explanation of how to attach to + global module. + +2025-06-26 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cxx_initialize_diagnostics): Use + diagnostic_context::set_adjust_diagnostic_info_callback. + +2025-06-26 Jakub Jelinek <jakub@redhat.com> + + * cp-trait.def: Implement C++26 P2830R10 - Constexpr Type Ordering. + (TYPE_ORDER): New. + * method.cc (type_order_value): Define. + * cp-tree.h (type_order_value): Declare. + * semantics.cc (trait_expr_value): Use gcc_unreachable also + for CPTK_TYPE_ORDER, adjust comment. + (finish_trait_expr): Handle CPTK_TYPE_ORDER. + * constraint.cc (diagnose_trait_expr): Likewise. + +2025-06-25 Martin Jambor <mjambor@suse.cz> + + * coroutines.h (class cp_coroutine_transform): Remove member + orig_fn_body. + +2025-06-24 Jakub Jelinek <jakub@redhat.com> + + PR c++/120773 + * decl.cc (grokfndecl): Implement C++26 P3618R0 - Allow attaching + main to the global module. Only pedwarn for current_lang_name + other than lang_name_cplusplus and adjust pedwarn wording. + +2025-06-23 Tobias Burnus <tburnus@baylibre.com> + + * parser.cc (OACC_WAIT_CLAUSE_MASK): Ass if clause. + +2025-06-18 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/115908 + PR c++/118074 + PR c++/95615 + * coroutines.cc (coro_frame_refcount_id): New. + (coro_init_identifiers): Initialise coro_frame_refcount_id. + (build_actor_fn): Set up initial_await_resume_called. Handle + decrementing of the frame reference count. Return directly to + the caller if that is non-zero. + (cp_coroutine_transform::wrap_original_function_body): Use a + conditional eh-only cleanup around the initial await expression + to release the body use on exception before initial await + resume. + (cp_coroutine_transform::build_ramp_function): Wrap the called + body in a cleanup that releases a use of the frame when we + return to the ramp. Implement frame, promise and argument copy + destruction via conditional cleanups when the frame use count + is zero. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (struct coroutine_info): Update comments. + (struct coro_aw_data): Remove self_handle and add in + information to create the handle in lowering. + (expand_one_await_expression): Build a temporary coroutine + handle. + (build_actor_fn): Remove reference to the frame copy of the + coroutine handle. + (cp_coroutine_transform::wrap_original_function_body): Remove + reference to the frame copy of the coroutine handle. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_expression_awaits): Elide assume + attributes containing await expressions, since these have + side effects. Emit a diagnostic that this has been done. + +2025-06-17 Jason Merrill <jason@redhat.com> + + PR c++/120678 + * cp-trait.def (IS_TRIVIALLY_DESTRUCTIBLE): Fix nargs. + +2025-06-17 Jason Merrill <jason@redhat.com> + + * module.cc (module_state::write_diagnostic_classification): New. + (module_state::write_begin): Call it. + (module_state::read_diagnostic_classification): New. + (module_state::read_initial): Call it. + (dk_string, dump_dc_change): New. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (finish_co_await_expr): Do not allow in an + unevaluated context. + (finish_co_yield_expr): Likewise. + +2025-06-17 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120273 + * coroutines.cc + (cp_coroutine_transform::wrap_original_function_body): Use + function start and end locations when synthesizing code. + (cp_coroutine_transform::cp_coroutine_transform): Set the + function end location. + +2025-06-16 Jason Merrill <jason@redhat.com> + + * constraint.cc (failed_completions_map): New. + (note_failed_type_completion): Rename from + note_failed_type_completion_for_satisfaction. Add + -Wsfinae-incomplete handling. + (failed_completion_location): New. + * class.cc (finish_struct_1): Add -Wsfinae-incomplete warning. + * decl.cc (require_deduced_type): Adjust. + (finish_function): Add -Wsfinae-incomplete warning. + * typeck.cc (complete_type_or_maybe_complain): Adjust. + (cxx_sizeof_or_alignof_type): Call note_failed_type_completion. + * pt.cc (dependent_template_arg_p): No longer static. + * cp-tree.h: Adjust. + +2025-06-16 yxj-github-437 <2457369732@qq.com> + + * parser.cc (cp_parser_asm_operand_list): Check for unexpanded + parameter packs. + +2025-06-14 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_co_await): Identify diagnostics + for initial and final await expressions. + (cp_coroutine_transform::wrap_original_function_body): Do + not handle initial and final await expressions here ... + (cp_coroutine_transform::apply_transforms): ... handle them + here and avoid duplicate diagnostics. + * coroutines.h: Declare inital and final await expressions + in the transform class. Save the function closing brace + location. + +2025-06-13 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/116775 + * coroutines.cc (analyze_expression_awaits): When we see + a builtin_constant_p call, and that contains one or more + await expressions, then replace the call with its result + and discard the unevaluated operand. + +2025-06-13 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Set can_throw. + +2025-06-12 Alfie Richards <alfie.richards@arm.com> + + * decl.cc (maybe_version_functions): Change record_function_versions + call to add_function_version. + +2025-06-12 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (union lang_type::maybe_objc_info): New type. + (struct lang_type): Use union maybe_objc_info info member + instead of tree objc_info. + * lex.cc (copy_lang_type): Use sizeof (struct lang_type) + just for ObjC++ and otherwise offsetof (struct lang_type, info). + (maybe_add_lang_type_raw): Likewise. + (cxx_make_type): Formatting fix. + +2025-06-09 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120495 + PR c++/115605 + * pt.cc (lookup_template_class): Honour provided namespace contexts + when looking up class templates. + +2025-06-06 Jason Merrill <jason@redhat.com> + + PR c++/120555 + * decl2.cc (fn_being_defined, fn_template_being_defined): New. + (mark_used): Check fn_template_being_defined. + +2025-06-05 Patrick Palka <ppalka@redhat.com> + + PR c++/120224 + * pt.cc (tsubst_function_decl): Return error_mark_node if + substituting into the formal parameter list failed. + (tsubst_decl) <case PARM_DECL>: Return error_mark_node + upon TREE_TYPE substitution failure, when in a SFINAE + context. Return error_mark_node upon DECL_CHAIN substitution + failure. + +2025-06-05 Patrick Palka <ppalka@redhat.com> + + PR c++/118340 + * constexpr.cc (maybe_constant_value): First try looking up each + operand in the cv_cache and reusing the result. + +2025-06-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_fn_parms): Move from free function.. + (cp_coroutine_transform::analyze_fn_parms):... to method. + (cp_coroutine_transform::apply_transforms): Adjust call to + analyze_fn_parms. + * coroutines.h: Declare analyze_fn_parms. + +2025-06-05 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (expand_one_await_expression): Set the + initial_await_resume_called flag here. + (build_actor_fn): Populate the frame accessor for the + initial_await_resume_called flag. + (cp_coroutine_transform::wrap_original_function_body): Do + not modify the initial_await expression to include the + initial_await_resume_called flag here. + +2025-06-04 Jason Merrill <jason@redhat.com> + + PR c++/120502 + * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation + before genericize. + * constexpr.cc (cxx_eval_store_expression): Add comment. + +2025-06-03 Jason Merrill <jason@redhat.com> + + * name-lookup.h (operator|, operator|=): Define for WMB_Flags. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Fix refs and arrays of unknown + bound. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/120506 + * constexpr.cc (cxx_eval_outermost_constant_expr): Always check + CONSTRUCTOR_NO_CLEARING. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (build_actor_fn): Remove an unused + label, guard the frame deallocation correctly, use + simpler APIs to build if and return statements. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/118903 + * constexpr.cc (potential_constant_expression_1): Emit + an error when co_await et. al. are used in constexpr + contexts. + +2025-06-02 Iain Sandoe <iain@sandoe.co.uk> + + * error.cc (dump_expr): Add co_await, co_yield and co_return. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * method.cc (destructible_expr): Handle non-classes. + (constructible_expr): Check for abstract class here... + (is_xible_helper): ...not here. + +2025-06-02 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]: + Add cp_unevaluated. + +2025-06-02 Sandra Loosemore <sloosemore@baylibre.com> + + * cp-tree.h (maybe_convert_cond): Declare. + * parser.cc (cp_parser_omp_context_selector): Call + maybe_convert_cond and fold_build_cleanup_point_expr on the + expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. + * pt.cc (tsubst_omp_context_selector): Likewise. + * semantics.cc (maybe_convert_cond): Remove static declaration. + +2025-05-30 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (lambda_capture_field_type): Handle 'this' normally. + (build_capture_proxy): Special-case 'this' by-ref capture more. + (nonlambda_method_basetype): Look through xobj lambdas. + +2025-05-30 Julian Brown <julian@codesourcery.com> + Tobias Burnus <tburnus@baylibre.com> + + * constexpr.cc (reduced_constant_expression_p): Add OMP_DECLARE_MAPPER + case. + (cxx_eval_constant_expression, potential_constant_expression_1): + Likewise. + * cp-gimplify.cc (cxx_omp_finish_mapper_clauses): New function. + * cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES, + LANG_HOOKS_OMP_MAPPER_LOOKUP, LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE, + LANG_HOOKS_OMP_MAP_ARRAY_SECTION): Define langhooks. + * cp-tree.h (lang_decl_base): Add omp_declare_mapper_p field. Recount + spare bits comment. + (DECL_OMP_DECLARE_MAPPER_P): New macro. + (omp_mapper_id): Add prototype. + (cp_check_omp_declare_mapper): Add prototype. + (omp_instantiate_mappers): Add prototype. + (cxx_omp_finish_mapper_clauses): Add prototype. + (cxx_omp_mapper_lookup): Add prototype. + (cxx_omp_extract_mapper_directive): Add prototype. + (cxx_omp_map_array_section): Add prototype. + * decl.cc (check_initializer): Add OpenMP declare mapper support. + (cp_finish_decl): Set DECL_INITIAL for OpenMP declare mapper var decls + as appropriate. + * decl2.cc (mark_used): Instantiate OpenMP "declare mapper" magic var + decls. + * error.cc (dump_omp_declare_mapper): New function. + (dump_simple_decl): Use above. + * parser.cc (cp_parser_omp_clause_map): Add KIND parameter. Support + "mapper" modifier. + (cp_parser_omp_all_clauses): Add KIND argument to + cp_parser_omp_clause_map call. + (cp_parser_omp_target): Call omp_instantiate_mappers before + finish_omp_clauses. + (cp_parser_omp_declare_mapper): New function. + (cp_parser_omp_declare): Add "declare mapper" support. + * pt.cc (tsubst_decl): Adjust name of "declare mapper" magic var decls + once we know their type. + (tsubst_omp_clauses): Call omp_instantiate_mappers before + finish_omp_clauses, for target regions. + (tsubst_expr): Support OMP_DECLARE_MAPPER nodes. + (instantiate_decl): Instantiate initialiser (i.e definition) for OpenMP + declare mappers. + * semantics.cc (gimplify.h): Include. + (omp_mapper_id, omp_mapper_lookup, omp_extract_mapper_directive, + cxx_omp_map_array_section, cp_check_omp_declare_mapper): New functions. + (finish_omp_clauses): Delete GOMP_MAP_PUSH_MAPPER_NAME and + GOMP_MAP_POP_MAPPER_NAME artificial clauses. + (omp_target_walk_data): Add MAPPERS field. + (finish_omp_target_clauses_r): Scan for uses of struct/union/class type + variables. + (finish_omp_target_clauses): Create artificial mapper binding clauses + for used structs/unions/classes in offload region. + +2025-05-29 David Malcolm <dmalcolm@redhat.com> + + * error.cc (cxx_format_postprocessor::clone): Update to use + unique_ptr. + (cxx_dump_pretty_printer::cxx_dump_pretty_printer): Likewise. + (cxx_initialize_diagnostics): Likewise. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/113563 + * lambda.cc (build_capture_proxy): Check pointerness of the + member, not the proxy type. + (lambda_expr_this_capture): Don't assume current_class_ref. + (nonlambda_method_basetype): Likewise. + * semantics.cc (finish_non_static_data_member): Don't assume + TREE_TYPE (object) is set. + (finish_this_expr): Check current_class_type for lambda, + not current_class_ref. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/109283 + * coroutines.cc (find_any_await): Only save the statement + pointer if the caller passes a place for it. + (flatten_await_stmt): When checking that ternary expressions + have been handled, also check that they contain a co_await. + +2025-05-29 Jason Merrill <jason@redhat.com> + + * decl.cc (start_decl): Also set invalid_constexpr + for maybe_constexpr_fn. + * parser.cc (cp_parser_jump_statement): Likewise. + * constexpr.cc (potential_constant_expression_1): Ignore + goto to an artificial label. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + * parser.cc (cp_parser_omp_metadirective): Do not call + cp_parser_skip_to_end_of_block_or_statement after an error. + +2025-05-29 Sandra Loosemore <sloosemore@baylibre.com> + + PR c/120180 + * parser.cc (cp_parser_omp_metadirective): Only consume the + token if it is the expected close paren. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (analyze_fn_parms): No longer + create a parameter copy guard var. + * coroutines.h (struct param_info): Remove the + entry for the parameter copy destructor guard. + +2025-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/120453 + * cp-tree.h (DECL_RAMP_P): New. + * typeck.cc (check_return_expr): Use DECL_RAMP_P instead + of DECL_RAMP_FN. + +2025-05-29 Jason Merrill <jason@redhat.com> + + PR c++/107600 + * cp-trait.def (IS_DESTRUCTIBLE, IS_NOTHROW_DESTRUCTIBLE) + (IS_TRIVIALLY_DESTRUCTIBLE): New. + * constraint.cc (diagnose_trait_expr): Explain them. + * method.cc (destructible_expr): New. + (is_xible_helper): Use it. + * semantics.cc (finish_trait_expr): Handle new traits. + (trait_expr_value): Likewise. Complain about asking + whether a deleted dtor is trivial. + +2025-05-28 Jason Merrill <jason@redhat.com> + + * module.cc (module_state::write_namespaces): Write + using-directives. + (module_state::read_namespaces): And read them. + * name-lookup.cc (add_using_namespace): Add overload. Build a + USING_DECL for modules. + (name_lookup::search_usings, name_lookup::queue_usings) + (using_directives_contain_std_p): Strip the USING_DECL. + * name-lookup.h: Declare it. + * parser.cc (cp_parser_import_declaration): Set MK_EXPORTING + for export import. + +2025-05-27 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc (cp_coroutine_transform::build_ramp_function): + Replace TRUTH_AND_EXPR with TRUTH_ANDIF_EXPR in three places. + +2025-05-26 Tobias Burnus <tburnus@baylibre.com> + + PR c++/120413 + * semantics.cc (finish_omp_target_clauses_r): Handle + BIND_EXPR with empty BIND_EXPR_BLOCK. + +2025-05-26 Jason Merrill <jason@redhat.com> + + * cp-tree.h: Declare tinst_dump_id. + * cp-objcp-common.cc (cp_register_dumps): Set it. + * pt.cc (push_tinst_level_loc): Dump it. + (reopen_tinst_level): Here too. + (tinst_complete_p): New. + (instantiate_pending_templates): Don't reopen_tinst_level for + already-complete instantiations. + +2025-05-26 Jason Merrill <jason@redhat.com> + + * cp-tree.h (class cxx_dump_pretty_printer): New. + * error.cc (cxx_dump_pretty_printer): Ctor/dtor definitions. + +2025-05-25 Jason Merrill <jason@redhat.com> + + * error.cc (dump_template_bindings): Correct skipping of + redundant bindings. + +2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120363 + * decl2.cc (get_tls_init_fn): Set context as global_namespace. + (get_tls_wrapper_fn): Likewise. + +2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120414 + * module.cc (trees_in::tree_node): Allow reading a USING_DECL + when streaming tt_data_member. + +2025-05-23 Jason Merrill <jason@redhat.com> + + * mangle.cc (mangle_decl_string): Don't push_tinst_level. + +2025-05-22 Jason Merrill <jason@redhat.com> + + PR c++/120935 + * cp-gimplify.cc (cp_fold): Check always_inline. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Replace ramp + cleanup try-catch block with eh-only cleanup statements. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc + (cp_coroutine_transform::build_ramp_function): Use + decltype(auto) to determine the type of the temporary + get_return_object. + +2025-05-21 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/119916 + * coroutines.cc + (cp_coroutine_transform::wrap_original_function_body): Do not + initialise initial_await_resume_called here... + (cp_coroutine_transform::build_ramp_function): ... but here. + When the coroutine is not void, initialize a GRO object from + promise.get_return_object(). Use this as the argument to the + return expression. Use a regular cleanup for the GRO, since + it is ramp-local. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120349 + * module.cc (trees_out::core_bools): Always mark vtables as + DECL_EXTERNAL. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120013 + * module.cc (trees_in::install_entity): Handle re-registering + the inner TYPE_DECL of a partial specialisation. + +2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120350 + * rtti.cc (get_tinfo_decl_direct): Mark TREE_ADDRESSABLE. + +2025-05-16 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Do the conversion unconditionally, even for same-type cases. + +2025-05-16 Iain Sandoe <iain@sandoe.co.uk> + + * typeck.cc (check_return_expr): Suppress conversions for NVRO + in coroutine ramp functions. + +2025-05-16 Iain Sandoe <iain@sandoe.co.uk> + + * decl.cc (poplevel): Set BLOCK_OUTER_CURLY_BRACE_P on the + body block for functions with no subblocks. + +2025-05-16 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (importer_interface): Adjust flags. + (get_importer_interface): Rename flags. + (trees_out::core_bools): Clean up special casing. + (trees_out::write_function_def): Rename flag. + +2025-05-15 Patrick Palka <ppalka@redhat.com> + + PR c++/120161 + * pt.cc (unify) <case RECORD_TYPE>: When comparing specializations + of a non-primary template, still perform a type comparison. + +2025-05-15 Jason Merrill <jason@redhat.com> + + * module.cc (trees_out::lang_decl_bools): Stream implicit_constexpr. + (trees_in::lang_decl_bools): Likewise. + (trees_in::is_matching_decl): Check it. + +2025-05-15 Jason Merrill <jason@redhat.com> + + PR c++/99599 + * pt.cc (conversion_may_instantiate_p): Make sure + classes are complete. + +2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Remove a remnant comment. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120125 + * module.cc (trees_out::write_function_def): Only set + DECL_NOT_REALLY_EXTERN if the importer might need to emit it. + * optimize.cc (maybe_thunk_body): Don't assume 'fn' has a cgraph + node created. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119864 + * decl2.cc (start_objects): Only use module initialized for + host. + (c_parse_final_cleanups): Don't always create an OMP offload + init function in modules. + +2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com> + + * name-lookup.cc (lookup_imported_hidden_friend): Add back + lazy_load_pendings with comment. + +2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com> + + * cp-gimplify.cc (cp_fold): Add to_underlying. + +2025-05-14 Owen Avery <powerboat9.gamer@gmail.com> + Jason Merrill <jason@redhat.com> + + * method.cc (synthesized_method_walk): Check whether + -Wvirtual-move-assign is enabled at the location of a base + class's move assignment operator. + +2025-05-12 Jason Merrill <jason@redhat.com> + + PR c++/120012 + * class.cc (check_non_pod_aggregate): Check is_empty_class. + +2025-05-10 Jason Merrill <jason@redhat.com> + + PR c++/120204 + * pt.cc (tsubst_baselink): Always error if lookup fails. + +2025-05-09 Jason Merrill <jason@redhat.com> + + * decl2.cc (determine_visibility): Ignore args for friend templates. + +2025-05-09 Jason Merrill <jason@redhat.com> + + PR c++/99599 + PR c++/120185 + * class.cc (type_has_converting_constructor): Handle null parm. + * pt.cc (fn_type_unification): Skip early non-dep checking if + no concepts. + +2025-05-08 Jason Merrill <jason@redhat.com> + + PR c++/99599 + * cp-tree.h (type_has_converting_constructor): Declare. + * class.cc (type_has_converting_constructor): New. + * pt.cc (conversion_may_instantiate_p): Don't check completeness. + +2025-05-05 Simon Martin <simon@nasilyan.com> + + * cp-tree.h (parsing_default_capturing_generic_lambda_in_template): + Remove obsolete prototype. + +2025-05-02 Jason Merrill <jason@redhat.com> + + PR c++/115207 + * decl.cc (cp_finish_decl): Call layout_decl after CTAD. + +2025-05-02 Jason Merrill <jason@redhat.com> + + PR c++/120012 + * cp-tree.h (struct lang_type): Add non_aggregate_pod. + (CLASSTYPE_NON_AGGREGATE_POD): New. + * class.cc (check_bases_and_members): Set it. + (check_non_pod_aggregate): Diagnose it. + +2025-05-02 Jakub Jelinek <jakub@redhat.com> + + PR c++/117827 + * init.cc (build_vec_init): Push to *cleanup_flags clearing of rval + instead of setting of iterator to maxindex. + +2025-05-01 Patrick Palka <ppalka@redhat.com> + + * constexpr.cc (explain_invalid_constexpr_fn): In the + DECL_CONSTRUCTOR_P branch pass the non-genericized body to + require_potential_constant_expression. + +2025-05-01 Patrick Palka <ppalka@redhat.com> + + PR c++/119034 + PR c++/68942 + * pt.cc (tsubst_expr) <case CALL_EXPR>: Revert PR68942 fix. + * semantics.cc (finish_call_expr): Ensure the callee of an + ADL-enabled call is wrapped in an OVERLOAD. + +2025-05-01 Jason Merrill <jason@redhat.com> + + * Make-lang.in: Don't pass the full path to gperf. + * std-name-hint.h: Regenerate. + +2025-05-01 Jason Merrill <jason@redhat.com> + + PR c++/119162 + * constexpr.cc (find_deleted_heap_var): Remove. + (cxx_eval_call_expression): Don't call it. Don't set TREE_STATIC on + heap vars. + (cxx_eval_outermost_constant_expr): Don't mess with varpool. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/120023 + * module.cc (depset::hash::find_dependencies): Also call + add_deduction_guides when walking one. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119938 + * pt.cc (get_template_parm_object): When !check_init, add assert + that expr really is constant and mark decl as such. + +2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119551 + PR c++/119996 + * module.cc (depset::hash::make_dependency): Also mark inline + variables referencing TU-local values as exposures here. + (depset::hash::finalize_dependencies): Add error message for + inline variables. + +2025-04-30 Patrick Palka <ppalka@redhat.com> + + PR c++/119981 + PR c++/119378 + * pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Substitute + into template parameter list first. When substituting the + context, only set processing_template_decl if there's more + than one level of introduced template parameters. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * parser.cc: Include "analyzer/analyzer-language.h". + (ana::cp_translation_unit): New class. + (cp_parser_translation_unit): Add call to + ana::on_finish_translation_unit. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * cxx-pretty-print.cc: Drop include of "make-unique.h". + Replace uses of ::make_unique with std::make_unique. + * error.cc: Likewise. + * name-lookup.cc: Likewise. + * parser.cc: Likewise. + +2025-04-28 David Malcolm <dmalcolm@redhat.com> + + * name-lookup.cc: Include "make-unique.h". + (namespace_hints::convert_candidates_to_name_hint): Use + ::make_unique rather than "new" when making + show_candidate_location and suggest_alternatives. + (namespace_hints::maybe_decorate_with_limit): Likewise when making + namespace_limit_reached. + (suggest_alternatives_for_1): Likewise when making + suggest_missing_option. + (maybe_suggest_missing_std_header): Likewise when making + missing_std_header. + (macro_use_before_def::maybe_make): Use std::unique_ptr. + (macro_use_before_def::macro_use_before_def): Make public. + (lookup_name_fuzzy): Use ::make_unique rather than "new" when + making suggest_missing_header. + * parser.cc: Include "make-unique.h". + (cp_parser_error_1): Use ::make_unique rather than "new" when + making suggest_missing_header. + +2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119939 + * module.cc (trees_out::lang_decl_vals): Also stream + lang->u.fn.context when DECL_UNIQUE_FRIEND_P. + (trees_in::lang_decl_vals): Likewise. + +2025-04-27 H.J. Lu <hjl.tools@gmail.com> + + PR middle-end/112877 + * call.cc (type_passed_as): Remove the + targetm.calls.promote_prototypes call. + (convert_for_arg_passing): Likewise. + * typeck.cc (cxx_safe_arg_type_equiv_p): Likewise. + +2025-04-25 Jason Merrill <jason@redhat.com> + + PR c++/119764 + PR c++/87185 + * lambda.cc (insert_capture_proxy): Handle noexcept lambda. + (prune_lambda_captures): Likewise, in ABI v21. + +2025-04-25 Jason Merrill <jason@redhat.com> + + * cp-tree.h (struct tinst_level): Add had_errors bit. + * pt.cc (push_tinst_level_loc): Clear it. + (pop_tinst_level): Set it. + (reopen_tinst_level): Check it. + (instantiate_pending_templates): Call limit_bad_template_recursion. + +2025-04-24 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Return early if + not enabled. + +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + * name-lookup.cc (lookup_imported_hidden_friend): Remove + unnecessary lazy_load_pendings. + +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119863 + * name-lookup.cc (get_mergeable_namespace_binding): Remove + no-longer-used function. + (lookup_imported_hidden_friend): Also look for hidden imported + decls in an attached decl's module. + +2025-04-21 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Move + verify_constant later. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/118775 + * constexpr.cc (cxx_eval_call_expression): Add assert. + (fold_to_constant): Handle processing_template_decl. + * init.cc (build_new_1): Use fold_to_constant. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/99456 + * constexpr.cc (cxx_eval_constant_expression): Check strict + instead of manifestly_const_eval. + (maybe_constant_init_1): Be strict for static constexpr vars. + +2025-04-19 Jason Merrill <jason@redhat.com> + + * coroutines.cc (coro_build_expr_stmt) + (coro_build_cvt_void_expr_stmt): Remove. + (build_actor_fn): Use finish_expr_stmt. + * semantics.cc (finish_expr_stmt): Avoid wrapping statement in + EXPR_STMT. + (finish_stmt_expr_expr): Add comment. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (is_valid_constexpr_fn): Improve diagnostic. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Give both + expression and allocation location in allocated storage diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * name-lookup.cc (name_lookup::preserve_state): Fix reserve call. + * rtti.cc (get_tinfo_desc): Use vec_safe_grow_cleared. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * semantics.cc (finish_type_pack_element): Add more info + to diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * decl.cc (cp_make_fname_decl): Prevent silent failure. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * lex.cc (unqualified_name_lookup_error): Handle 'requires' better. + +2025-04-17 Jason Merrill <jason@redhat.com> + + PR c++/113360 + * cp-tree.h (struct language_function): Add erroneous bit. + * constexpr.cc (explain_invalid_constexpr_fn): Return if set. + (cxx_eval_call_expression): Quiet if set. + * parser.cc (cp_parser_function_definition_after_declarator) + * pt.cc (instantiate_body): Set it. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/114772 + PR c++/101180 + * pt.cc (apply_late_template_attributes): Also override + target_option_current_node. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Preserve flags + on the attribute list. + +2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119755 + * lambda.cc (prune_lambda_captures): Remove pruned capture from + function's BLOCK_VARS and BIND_EXPR_VARS. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/111075 + * constexpr.cc (cxx_eval_call_expression): Allow trivial + call from a thunk. + +2025-04-15 Patrick Palka <ppalka@redhat.com> + + PR c++/119807 + PR c++/112288 + * pt.cc (tsubst_friend_function): Skip remapping an + existing specialization if it doesn't match the shape of + the new friend definition. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/113835 + * constexpr.cc (cxx_eval_outermost_constant_expr): Bail out early + for std::vector(N). + +2025-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/99214 + * constraint.cc (satisfy_declaration_constraints): Pass the + original ARGS to push_tinst_level. + +2025-04-13 Patrick Palka <ppalka@redhat.com> + + PR c++/115639 + * constexpr.cc (struct constexpr_call): Add NSDMIs to each + field. Replace 'result' data member with 3-element 'results' + array and a 'result' accessor function. Remove + 'manifestly_const_eval' data member. + (constexpr_call_hasher::equal): Adjust after constexpr_call + layout change. + (cxx_eval_call_expression): Likewise. Define some local + variables closer to their first use. Use unknown_type_node + instead of NULL_TREE as the "in progress" result. After + successully evaluating a call with mce_unknown, also cache the + result in the corresponding mce_true and mce_false slots. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Don't check for + mismatches when importing a DECL_MAYBE_DELETED function over one + that's already finished. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Add custom errors for + different kinds of mismatches. + +2025-04-12 Patrick Palka <ppalka@redhat.com> + + PR c++/116416 + * constexpr.cc (maybe_constant_init_1): Generalize type of + of manifestly_const_eval parameter from bool to mce_value. + (maybe_constant_init): Define 3-parameter version taking a + manifestly_const_eval instead of bool parameter. + (cxx_constant_init): Adjust. + * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false + to maybe_constant_init during prvalue folding if ff_mce_false is + set. + * cp-tree.h (maybe_constant_init): Declare new overload. + +2025-04-11 Jason Merrill <jason@redhat.com> + + PR c++/114970 + * cp-gimplify.cc (cp_build_init_expr_for_ctor): Suppress warnings on + return_this COMPOUND_EXPR. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119345 + * pt.cc (add_extra_args): Also register a specialization + of the captured variable. + +2025-04-10 Patrick Palka <ppalka@redhat.com> + + PR c++/119687 + * pt.cc (alias_ctad_tweaks): Use lkp_range / lkp_iterator + instead of ovl_iterator. + +2025-04-10 Jakub Jelinek <jakub@redhat.com> + + PR translation/119684 + * error.cc (cp_print_error_function): Use G_ instead of _ for + pp_printf arguments. + (function_category): Use G_ instead of _. + (print_instantiation_full_context): Use G_ instead of _ in pp_verbatim + arguments. + (print_location): Likewise. + (print_instantiation_partial_context): Likewise. + (maybe_print_constexpr_context): Likewise. + (print_constrained_decl_info): Use G_() around pp_verbatim argument. + (print_concept_check_info): Likewise. + (print_constraint_context_head): Likewise. + (print_requires_expression_info): Likewise. Merge separate pp_verbatim + "in requirements " and "with " into one with conditional messages. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119175 + * mangle.cc (decl_mangling_context): Look through lambda type. + +2025-04-09 Patrick Palka <ppalka@redhat.com> + + PR c++/119574 + * pt.cc (add_extra_args): Remove checking assert. + +2025-04-09 Jason Merrill <jason@redhat.com> + + PR c++/118698 + * constraint.cc (struct norm_info): Add tf_partial. + * pt.cc (any_template_parm_r): Handle LAMBDA_EXPR_EXTRA_ARGS. + 2025-04-08 Jason Merrill <jason@redhat.com> PR c++/117530 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..02cef63 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -220,7 +220,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree, bool, tree, tree, int, struct z_candidate **, tsubst_flags_t); static conversion *merge_conversion_sequences (conversion *, conversion *); -static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t); +static tree build_temp (tree, tree, int, enum diagnostics::kind *, + tsubst_flags_t); static conversion *build_identity_conv (tree, tree); static inline bool conv_binds_to_array_of_unknown_bound (conversion *); static bool conv_is_prvalue (conversion *); @@ -412,6 +413,7 @@ build_call_a (tree function, int n, tree *argarray) /* We're disconnecting the initializer from its target, don't create a temporary. */ arg = TARGET_EXPR_INITIAL (arg); + suppress_warning (arg, OPT_Wunused_result); tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t); CALL_EXPR_ARG (function, i) = arg; @@ -1723,6 +1725,56 @@ involves_qualification_conversion_p (tree to, tree from) return false; } +/* Return true if HANDLER is a match for exception object with EXCEPT_TYPE as + per [except.handle]/3. */ + +bool +handler_match_for_exception_type (tree handler, tree except_type) +{ + tree handler_type = HANDLER_TYPE (handler); + if (handler_type == NULL_TREE) + return true; /* ... */ + if (same_type_ignoring_top_level_qualifiers_p (handler_type, except_type)) + return true; + if (CLASS_TYPE_P (except_type) && CLASS_TYPE_P (handler_type)) + { + base_kind b_kind; + tree binfo = lookup_base (except_type, handler_type, ba_check, &b_kind, + tf_none); + if (binfo && binfo != error_mark_node) + return true; + } + if (TYPE_PTR_P (handler_type) || TYPE_PTRDATAMEM_P (handler_type)) + { + if (TREE_CODE (except_type) == NULLPTR_TYPE) + return true; + if ((TYPE_PTR_P (handler_type) && TYPE_PTR_P (except_type)) + || (TYPE_PTRDATAMEM_P (handler_type) + && TYPE_PTRDATAMEM_P (except_type))) + { + conversion *conv + = standard_conversion (handler_type, except_type, NULL_TREE, + /*c_cast_p=*/false, 0, tf_none); + if (conv && !conv->bad_p) + { + for (conversion *t = conv; t; t = next_conversion (t)) + switch (t->kind) + { + case ck_ptr: + case ck_fnptr: + case ck_qual: + case ck_identity: + break; + default: + return false; + } + return true; + } + } + } + return false; +} + /* A reference of the indicated TYPE is being bound directly to the expression represented by the implicit conversion sequence CONV. Return a conversion sequence for this binding. */ @@ -4876,6 +4928,11 @@ implicit_conversion_error (location_t loc, tree type, tree expr) && !CP_AGGREGATE_TYPE_P (type)) error_at (loc, "designated initializers cannot be used with a " "non-aggregate type %qT", type); + else if (is_stub_object (expr)) + /* The expression is generated by a trait check, we don't have + a useful location to highlight the label. */ + error_at (loc, "could not convert %qH to %qI", + TREE_TYPE (expr), type); else { range_label_for_type_mismatch label (TREE_TYPE (expr), type); @@ -6404,7 +6461,9 @@ build_conditional_expr (const op_location_t &loc, types when the enumeration is still being defined. */; else if (complain & (cxx_dialect >= cxx26 ? tf_warning_or_error : tf_warning)) - emit_diagnostic (cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), loc, OPT_Wenum_compare, "enumerated mismatch " "in conditional expression: %qT vs %qT", arg2_type, arg3_type); @@ -7435,7 +7494,16 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, else if (TREE_CODE (cand->fn) == FUNCTION_DECL) { if (overload) - *overload = cand->fn; + { + if (cand->rewritten ()) + /* build_min_non_dep_op_overload needs to know whether the + candidate is rewritten/reversed. */ + *overload = build_tree_list (build_int_cst (integer_type_node, + cand->flags), + cand->fn); + else + *overload = cand->fn; + } if (resolve_args (arglist, complain) == NULL) result = error_mark_node; @@ -7484,9 +7552,6 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, /* If this was a C++20 rewritten comparison, adjust the result. */ if (cand->rewritten ()) { - /* FIXME build_min_non_dep_op_overload can't handle rewrites. */ - if (overload) - *overload = NULL_TREE; switch (code) { case EQ_EXPR: @@ -7585,8 +7650,9 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, && (complain & tf_warning_or_error) == 0) result = error_mark_node; else if (cxx_dialect >= cxx26 || (complain & tf_warning)) - emit_diagnostic (cxx_dialect >= cxx26 - ? DK_PEDWARN : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), loc, OPT_Wenum_compare, "comparison between %q#T and %q#T", arg1_type, arg2_type); @@ -7838,28 +7904,6 @@ extract_call_expr (tree call) call = TREE_OPERAND (call, 0); if (TREE_CODE (call) == TARGET_EXPR) call = TARGET_EXPR_INITIAL (call); - if (cxx_dialect >= cxx20) - switch (TREE_CODE (call)) - { - /* C++20 rewritten comparison operators. */ - case TRUTH_NOT_EXPR: - call = TREE_OPERAND (call, 0); - break; - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case SPACESHIP_EXPR: - { - tree op0 = TREE_OPERAND (call, 0); - if (integer_zerop (op0)) - call = TREE_OPERAND (call, 1); - else - call = op0; - } - break; - default:; - } if (TREE_CODE (call) != CALL_EXPR && TREE_CODE (call) != AGGR_INIT_EXPR @@ -8400,11 +8444,11 @@ complain_about_access (tree decl, tree diag_decl, tree diag_location, static tree build_temp (tree expr, tree type, int flags, - diagnostic_t *diagnostic_kind, tsubst_flags_t complain) + enum diagnostics::kind *diagnostic_kind, tsubst_flags_t complain) { int savew, savee; - *diagnostic_kind = DK_UNSPECIFIED; + *diagnostic_kind = diagnostics::kind::unspecified; /* If the source is a packed field, calling the copy constructor will require binding the field to the reference parameter to the copy constructor, and @@ -8428,9 +8472,9 @@ build_temp (tree expr, tree type, int flags, expr = build_special_member_call (NULL_TREE, complete_ctor_identifier, &args, type, flags, complain); if (warningcount + werrorcount > savew) - *diagnostic_kind = DK_WARNING; + *diagnostic_kind = diagnostics::kind::warning; else if (errorcount > savee) - *diagnostic_kind = DK_ERROR; + *diagnostic_kind = diagnostics::kind::error; return expr; } @@ -8642,9 +8686,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, bool nested_p, tsubst_flags_t complain) { tree totype = convs->type; - diagnostic_t diag_kind; + enum diagnostics::kind diag_kind; int flags; location_t loc = cp_expr_loc_or_input_loc (expr); + const bool stub_object_p = is_stub_object (expr); if (convs->bad_p && !(complain & tf_error)) return error_mark_node; @@ -8721,7 +8766,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "from %qH to %qI", TREE_TYPE (expr), totype); if (complained) - print_z_candidate (loc, N_("candidate is:"), t->cand); + { + auto_diagnostic_nesting_level sentinel; + print_z_candidate (loc, N_("candidate is:"), t->cand); + } expr = convert_like (t, expr, fn, argnum, /*issue_conversion_warnings=*/false, /*c_cast_p=*/false, /*nested_p=*/true, @@ -8746,7 +8794,14 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, else if (t->kind == ck_identity) break; } - if (!complained && expr != error_mark_node) + if (!complained && stub_object_p) + { + /* An error diagnosed within a trait, don't give extra labels. */ + error_at (loc, "invalid conversion from %qH to %qI", + TREE_TYPE (expr), totype); + complained = 1; + } + else if (!complained && expr != error_mark_node) { range_label_for_type_mismatch label (TREE_TYPE (expr), totype); gcc_rich_location richloc (loc, &label, highlight_colors::percent_h); @@ -9169,7 +9224,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, if (convs->copy_init_p) flags |= LOOKUP_ONLYCONVERTING; expr = build_temp (expr, totype, flags, &diag_kind, complain); - if (diag_kind && complain) + if (diag_kind != diagnostics::kind::unspecified && complain) { auto_diagnostic_group d; maybe_print_user_conv_context (convs); @@ -9707,11 +9762,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 +9797,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)); @@ -14987,7 +15032,10 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups, /* P2718R0 - in C++23 for-range-initializer, extend all temps. */ if (DECL_NAME (decl) == for_range__identifier - && flag_range_for_ext_temps) + && flag_range_for_ext_temps + /* Iterating expansion statement decl is static right now, but that + could change depending on CWG3044 and CWG3043. */ + && !TREE_STATIC (decl)) { gcc_checking_assert (!cond_guard); return extend_all_temps (decl, init, cleanups); diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 2b694b9..cf58f65 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 @@ -1351,7 +1356,30 @@ add_method (tree type, tree method, bool via_using) if (!compparms (parms1, parms2)) continue; - if (!equivalently_constrained (fn, method)) + tree fn_constraints = get_constraints (fn); + tree method_constraints = get_constraints (method); + + if (fn_constraints && method_constraints + && DECL_CONTEXT (fn) != type + && !processing_template_decl) + { + if (TREE_CODE (fn) == TEMPLATE_DECL) + ++processing_template_decl; + if (tree outer_args = outer_template_args (fn)) + fn_constraints = tsubst_constraint_info (fn_constraints, + outer_args, + tf_warning_or_error, + fn); + if (tree outer_args = outer_template_args (method)) + method_constraints = tsubst_constraint_info (method_constraints, + outer_args, + tf_warning_or_error, + method); + if (TREE_CODE (fn) == TEMPLATE_DECL) + --processing_template_decl; + } + + if (!equivalent_constraints (fn_constraints, method_constraints)) { if (processing_template_decl) /* We can't check satisfaction in dependent context, wait until @@ -1402,7 +1430,7 @@ add_method (tree type, tree method, bool via_using) /* If these are versions of the same function, process and move on. */ if (TREE_CODE (fn) == FUNCTION_DECL - && maybe_version_functions (method, fn, true)) + && maybe_version_functions (method, fn)) continue; if (DECL_INHERITED_CTOR (method)) @@ -5724,6 +5752,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 +6485,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 +6507,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 +6782,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 +6895,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 +6909,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 +6921,31 @@ check_non_pod_aggregate (tree field) { location_t loc = DECL_SOURCE_LOCATION (next); if (DECL_FIELD_IS_BASE (next)) - warning_at (loc, OPT_Wabi,"offset of %qT base class for " - "%<-std=c++14%> and up changes in " - "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next)); + { + if (abi_version_crosses (17) + && CLASSTYPE_NON_POD_AGGREGATE (type)) + warning_at (loc, OPT_Wabi,"offset of %qT base class for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next)); + else if (abi_version_crosses (21) + && CLASSTYPE_NON_AGGREGATE_POD (type)) + warning_at (loc, OPT_Wabi,"offset of %qT base class for " + "%<-std=c++20%> and up changes in " + "%<-fabi-version=21%> (GCC 16)", TREE_TYPE (next)); + } else - warning_at (loc, OPT_Wabi, "offset of %qD for " - "%<-std=c++14%> and up changes in " - "%<-fabi-version=17%> (GCC 12)", next); + { + if (abi_version_crosses (17) + && CLASSTYPE_NON_POD_AGGREGATE (type)) + warning_at (loc, OPT_Wabi, "offset of %qD for " + "%<-std=c++14%> and up changes in " + "%<-fabi-version=17%> (GCC 12)", next); + else if (abi_version_crosses (21) + && CLASSTYPE_NON_AGGREGATE_POD (type)) + warning_at (loc, OPT_Wabi, "offset of %qD for " + "%<-std=c++20%> and up changes in " + "%<-fabi-version=21%> (GCC 16)", next); + } } } @@ -7367,7 +7475,7 @@ determine_key_method (tree type) && ! DECL_DECLARED_INLINE_P (method) && ! DECL_PURE_VIRTUAL_P (method)) { - CLASSTYPE_KEY_METHOD (type) = method; + SET_CLASSTYPE_KEY_METHOD (type, method); break; } @@ -7842,6 +7950,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 +8380,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 +10659,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 +10667,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 +11010,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 497f64f..701420c 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -153,7 +153,7 @@ static bool constexpr_error (location_t location, bool constexpr_fundef_p, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; rich_location richloc (line_table, location); va_start (ap, gmsgid); @@ -161,14 +161,17 @@ constexpr_error (location_t location, bool constexpr_fundef_p, if (!constexpr_fundef_p) { /* Report an error that cannot be suppressed. */ - diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR); + diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, + diagnostics::kind::error); ret = diagnostic_report_diagnostic (global_dc, &diagnostic); } else if (warn_invalid_constexpr) { diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - cxx_dialect < cxx23 ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = OPT_Winvalid_constexpr; + (cxx_dialect < cxx23 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning)); + diagnostic.m_option_id = OPT_Winvalid_constexpr; ret = diagnostic_report_diagnostic (global_dc, &diagnostic); } else @@ -303,11 +306,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 +1060,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 +1115,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 +1134,22 @@ explain_invalid_constexpr_fn (tree fun) struct GTY((for_user)) constexpr_call { /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; + constexpr_fundef *fundef = nullptr; /* Parameter bindings environment. A TREE_VEC of arguments. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. + tree bindings = NULL_TREE; + /* Result of the call, indexed by the value of + constexpr_ctx::manifestly_const_eval. + unknown_type_node means the call is being evaluated. error_mark_node means that the evaluation was erroneous or otherwise uncacheable (e.g. because it depends on the caller). Otherwise, the actual value of the call. */ - tree result; + tree results[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; /* The hash of this call; we remember it here to avoid having to recalculate it when expanding the hash table. */ - hashval_t hash; - /* The value of constexpr_ctx::manifestly_const_eval. */ - enum mce_value manifestly_const_eval; + hashval_t hash = 0; + + /* The result slot corresponding to the given mce_value. */ + tree& result (mce_value mce) { return results[1 + int(mce)]; } }; struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call> @@ -1170,6 +1187,10 @@ public: /* Heap VAR_DECLs created during the evaluation of the outermost constant expression. */ auto_vec<tree, 16> heap_vars; + /* Vector of caught exceptions, including exceptions still not active at + the start of a handler (those are immediately followed up by HANDLER_TYPE + until __cxa_begin_catch finishes). */ + auto_vec<tree, 2> caught_exceptions; /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */ vec<tree> *cleanups; /* If non-null, only allow modification of existing values of the variables @@ -1177,10 +1198,13 @@ public: hash_set<tree> *modifiable; /* Number of heap VAR_DECL deallocations. */ unsigned heap_dealloc_count; + /* Number of uncaught exceptions. */ + unsigned uncaught_exceptions; + /* Constructor. */ constexpr_global_ctx () : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr), - heap_dealloc_count (0) {} + heap_dealloc_count (0), uncaught_exceptions (0) {} bool is_outside_lifetime (tree t) { @@ -1294,6 +1318,48 @@ struct constexpr_ctx { mce_value manifestly_const_eval; }; +/* Predicates for the meaning of *jump_target. */ + +static bool +returns (tree *jump_target) +{ + return *jump_target && TREE_CODE (*jump_target) == RETURN_EXPR; +} + +static bool +breaks (tree *jump_target) +{ + return (*jump_target + && ((TREE_CODE (*jump_target) == LABEL_DECL + && LABEL_DECL_BREAK (*jump_target)) + || TREE_CODE (*jump_target) == BREAK_STMT + || TREE_CODE (*jump_target) == EXIT_EXPR)); +} + +static bool +continues (tree *jump_target) +{ + return (*jump_target + && ((TREE_CODE (*jump_target) == LABEL_DECL + && LABEL_DECL_CONTINUE (*jump_target)) + || TREE_CODE (*jump_target) == CONTINUE_STMT)); +} + +static bool +switches (tree *jump_target) +{ + return *jump_target && TREE_CODE (*jump_target) == INTEGER_CST; +} + +static bool +throws (tree *jump_target) +{ + /* void_node is for use in potential_constant_expression_1, otherwise + it should an artificial VAR_DECL created by constant evaluation + of __cxa_allocate_exception (). */ + return (*jump_target && (VAR_P (*jump_target) || *jump_target == void_node)); +} + /* True if the constexpr relaxations afforded by P2280R4 for unknown references and objects are in effect. */ @@ -1427,8 +1493,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); @@ -1531,13 +1595,671 @@ enum value_cat { }; static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, - value_cat, bool *, bool *, tree * = NULL); + value_cat, bool *, bool *, tree *); static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree, - value_cat, bool *, bool *); + value_cat, bool *, bool *, tree *); static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree, - bool * = NULL); + bool *, tree *); static tree find_heap_var_refs (tree *, int *, void *); -static tree find_deleted_heap_var (tree *, int *, void *); + +/* For exception object EXC if it has class type and usable what () method + which returns cv char * return the xmalloced string literal which it returns + if possible, otherwise return NULL. */ + +static char * +exception_what_str (const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (!CLASS_TYPE_P (type)) + return NULL; + tree std_exception = lookup_qualified_name (std_node, "exception", + LOOK_want::NORMAL, false); + if (TREE_CODE (std_exception) != TYPE_DECL) + return NULL; + if (!CLASS_TYPE_P (TREE_TYPE (std_exception))) + return NULL; + base_kind b_kind; + tree binfo = lookup_base (type, TREE_TYPE (std_exception), ba_check, &b_kind, + tf_none); + if (binfo == NULL_TREE || binfo == error_mark_node) + return NULL; + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + tree call + = finish_class_member_access_expr (exc, get_identifier ("what"), false, + tf_none); + if (call == error_mark_node) + return NULL; + releasing_vec what_args; + call = finish_call_expr (call, &what_args, false, false, tf_none); + if (call == error_mark_node) + return NULL; + if (TREE_CODE (TREE_TYPE (call)) != POINTER_TYPE + || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (call))) + || !COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (call))) + || !tree_int_cst_equal (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (call))), + TYPE_SIZE_UNIT (char_type_node)) + || TYPE_PRECISION (TREE_TYPE (TREE_TYPE (call))) != BITS_PER_UNIT) + return NULL; + if (!potential_constant_expression (call)) + return NULL; + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree ptr = cxx_eval_constant_expression (ctx, call, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) || non_constant_p) + return NULL; + if (reduced_constant_expression_p (ptr)) + if (const char *msg = c_getstr (ptr)) + return xstrdup (msg); + auto_vec <char, 32> v; + for (unsigned i = 0; i < INT_MAX; ++i) + { + tree t = call; + if (i) + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, size_int (i)); + t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); + non_constant_p = false; + overflow_p = false; + jmp_target = NULL; + tree t2 = cxx_eval_constant_expression (ctx, t, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) + || non_constant_p + || !tree_fits_shwi_p (t2)) + return NULL; + char c = tree_to_shwi (t2); + v.safe_push (c); + if (c == '\0') + break; + } + return xstrdup (v.address ()); +} + +/* Diagnose constant expression evaluation encountering call to + std::terminate due to exception EXC. */ + +static void +diagnose_std_terminate (location_t loc, const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (char *str = exception_what_str (ctx, exc)) + { + error_at (loc, "%qs called after throwing an exception of type %qT; " + "%<what()%>: %qs", "std::terminate", type, str); + free (str); + } + else + { + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + gcc_assert (!throws (&jmp_target) && !non_constant_p); + if (reduced_constant_expression_p (val)) + error_at (loc, "%qs called after throwing an exception %qE", + "std::terminate", val); + else + error_at (loc, "%qs called after throwing an exception of type %qT", + "std::terminate", type); + } +} + +/* Diagnose constant expression evaluation encountering call to + uncaught exception EXC. */ + +static void +diagnose_uncaught_exception (location_t loc, const constexpr_ctx *ctx, tree exc) +{ + tree type = strip_array_types (TREE_TYPE (exc)); + if (char *str = exception_what_str (ctx, exc)) + { + error_at (loc, "uncaught exception of type %qT; %<what()%>: %qs", type, str); + free (str); + } + else + { + if (type != TREE_TYPE (exc)) + exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL); + bool non_constant_p = false, overflow_p = false; + tree jmp_target = NULL; + tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue, + &non_constant_p, &overflow_p, + &jmp_target); + gcc_assert (!throws (&jmp_target) && !non_constant_p); + if (reduced_constant_expression_p (val)) + error_at (loc, "uncaught exception %qE", val); + else + error_at (loc, "uncaught exception of type %qT", type); + } +} + +/* Kinds of __cxa_* functions (and a few other EH related ones) we handle as + magic constexpr functions for C++26. */ + +enum cxa_builtin { + CXA_NONE = 0, + CXA_ALLOCATE_EXCEPTION = 1, + CXA_FREE_EXCEPTION = 2, + CXA_THROW = 3, + CXA_BEGIN_CATCH = 4, + CXA_END_CATCH = 5, + CXA_RETHROW = 6, + CXA_GET_EXCEPTION_PTR = 7, + CXA_BAD_CAST = 8, + CXA_BAD_TYPEID = 9, + CXA_THROW_BAD_ARRAY_NEW_LENGTH = 10, + STD_UNCAUGHT_EXCEPTIONS = 11, + STD_CURRENT_EXCEPTION = 12, + STD_RETHROW_EXCEPTION = 13, + BUILTIN_EH_PTR_ADJUST_REF = 14 +}; + +/* Return cxa_builtin if FNDECL is a __cxa_* function handled as + magic constexpr function for C++26. Return CXA_NONE otherwise. */ + +static enum cxa_builtin +cxx_cxa_builtin_fn_p (tree fndecl) +{ + if (cxx_dialect < cxx26) + return CXA_NONE; + if (DECL_LANGUAGE (fndecl) != lang_c) + { + if (!decl_in_std_namespace_p (fndecl)) + return CXA_NONE; + if (id_equal (DECL_NAME (fndecl), "uncaught_exceptions")) + return STD_UNCAUGHT_EXCEPTIONS; + if (id_equal (DECL_NAME (fndecl), "current_exception")) + return STD_CURRENT_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "rethrow_exception")) + return STD_RETHROW_EXCEPTION; + return CXA_NONE; + } + if (!startswith (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "__cxa_")) + return CXA_NONE; + if (id_equal (DECL_NAME (fndecl), "__cxa_allocate_exception")) + return CXA_ALLOCATE_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "__cxa_free_exception")) + return CXA_FREE_EXCEPTION; + if (id_equal (DECL_NAME (fndecl), "__cxa_throw")) + return CXA_THROW; + if (id_equal (DECL_NAME (fndecl), "__cxa_begin_catch")) + return CXA_BEGIN_CATCH; + if (id_equal (DECL_NAME (fndecl), "__cxa_end_catch")) + return CXA_END_CATCH; + if (id_equal (DECL_NAME (fndecl), "__cxa_rethrow")) + return CXA_RETHROW; + if (id_equal (DECL_NAME (fndecl), "__cxa_get_exception_ptr")) + return CXA_GET_EXCEPTION_PTR; + if (id_equal (DECL_NAME (fndecl), "__cxa_bad_cast")) + return CXA_BAD_CAST; + if (id_equal (DECL_NAME (fndecl), "__cxa_bad_typeid")) + return CXA_BAD_TYPEID; + if (id_equal (DECL_NAME (fndecl), "__cxa_throw_bad_array_new_length")) + return CXA_THROW_BAD_ARRAY_NEW_LENGTH; + return CXA_NONE; +} + +/* Helper function for cxx_eval_cxa_builtin_fn. + Check if ARG is a valid first argument of __cxa_throw or + __cxa_free_exception or __builtin_eh_ptr_adjust_ref. Return NULL_TREE if + not, otherwise return the artificial __cxa_allocate_exception allocated + VAR_DECL. FREE_EXC is true for __cxa_free_exception, false otherwise. */ + +static tree +cxa_check_throw_arg (tree arg, bool free_exc) +{ + STRIP_NOPS (arg); + if (TREE_CODE (arg) != ADDR_EXPR) + return NULL_TREE; + arg = TREE_OPERAND (arg, 0); + if (!VAR_P (arg) + || !DECL_ARTIFICIAL (arg) + || ((!free_exc || DECL_NAME (arg) != heap_uninit_identifier) + && DECL_NAME (arg) != heap_identifier) + || !DECL_LANG_SPECIFIC (arg)) + return NULL_TREE; + return arg; +} + +/* Helper function for cxx_eval_cxa_builtin_fn. + "Allocate" on the constexpr heap an exception object of TYPE + with REFCOUNT. */ + +static tree +cxa_allocate_exception (location_t loc, const constexpr_ctx *ctx, tree type, + tree refcount) +{ + tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier, type); + DECL_ARTIFICIAL (var) = 1; + retrofit_lang_decl (var); + DECL_EXCEPTION_REFCOUNT (var) = refcount; + ctx->global->heap_vars.safe_push (var); + return var; +} + +/* Evaluate various __cxa_* calls as magic constexpr builtins for + C++26 constexpr exception support (P3068R5). */ + +static tree +cxx_eval_cxa_builtin_fn (const constexpr_ctx *ctx, tree call, + enum cxa_builtin kind, tree fndecl, + bool *non_constant_p, bool *overflow_p, + tree *jump_target) +{ + int nargs = call_expr_nargs (call); + location_t loc = cp_expr_loc_or_input_loc (call); + tree args[4], arg; + if (nargs > 4) + { + invalid_nargs: + if (!ctx->quiet) + error_at (loc, "call to %qD function with incorrect" + "number of arguments", fndecl); + *non_constant_p = true; + return call; + } + if ((kind == CXA_BEGIN_CATCH || kind == CXA_GET_EXCEPTION_PTR) + && nargs == 1 + && (arg = CALL_EXPR_ARG (call, 0)) + && TREE_CODE (arg) == CALL_EXPR + && call_expr_nargs (arg) == 1 + && integer_zerop (CALL_EXPR_ARG (arg, 0))) + if (tree fun = get_function_named_in_call (arg)) + if (fndecl_built_in_p (fun, BUILT_IN_EH_POINTER)) + { + if (ctx->global->caught_exceptions.length () < 2) + { + no_caught_exceptions: + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions pending", + fndecl); + *non_constant_p = true; + return call; + } + /* Both __cxa_get_exception_ptr (__builtin_eh_pointer (0)) + and __cxa_begin_catch (__builtin_eh_pointer (0)) calls expect + ctx->global->caught_exceptions vector to end with + __cxa_allocate_exception created artificial VAR_DECL (the + exception object) followed by handler type, pushed by TRY_BLOCK + evaluation. The only difference between the functions is that + __cxa_begin_catch pops the handler type from the vector and keeps + the VAR_DECL last and decreases uncaught_exceptions. The + VAR_DECL after __cxa_begin_catch serves as the current exception + and is then popped in __cxa_end_catch evaluation. */ + tree handler_type = ctx->global->caught_exceptions.last (); + if (handler_type && VAR_P (handler_type)) + goto no_caught_exceptions; + unsigned idx = ctx->global->caught_exceptions.length () - 2; + arg = ctx->global->caught_exceptions[idx]; + gcc_assert (VAR_P (arg)); + if (kind == CXA_BEGIN_CATCH) + { + ctx->global->caught_exceptions.pop (); + --ctx->global->uncaught_exceptions; + } + if (handler_type == NULL_TREE) + /* Used for catch (...). Just return void. */ + return void_node; + else if (POINTER_TYPE_P (handler_type)) + { + /* Used for catch of a pointer. */ + if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE) + arg = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (arg)), arg, + size_zero_node, NULL_TREE, NULL_TREE); + arg = cp_convert (handler_type, arg, + ctx->quiet ? tf_none : tf_warning_or_error); + if (arg == error_mark_node) + { + *non_constant_p = true; + return call; + } + } + else + { + /* Used for catch of a non-pointer type. */ + tree exc_type = strip_array_types (TREE_TYPE (arg)); + tree exc_ptr_type = build_pointer_type (exc_type); + arg = build_fold_addr_expr_with_type (arg, exc_ptr_type); + if (CLASS_TYPE_P (handler_type)) + { + tree ptr_type = build_pointer_type (handler_type); + arg = cp_convert (ptr_type, arg, + ctx->quiet ? tf_none + : tf_warning_or_error); + if (arg == error_mark_node) + { + *non_constant_p = true; + return call; + } + } + } + return cxx_eval_constant_expression (ctx, arg, vc_prvalue, + non_constant_p, overflow_p, + jump_target); + } + for (int i = 0; i < nargs; ++i) + { + args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (call, i), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p) + return call; + if (*jump_target) + return NULL_TREE; + } + switch (kind) + { + case CXA_ALLOCATE_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + if (!tree_fits_uhwi_p (args[0])) + { + if (!ctx->quiet) + error_at (loc, "cannot allocate exception: size not constant"); + *non_constant_p = true; + return call; + } + else + { + tree type = build_array_type_nelts (char_type_node, + tree_to_uhwi (args[0])); + tree var = cxa_allocate_exception (loc, ctx, type, size_zero_node); + ctx->global->put_value (var, NULL_TREE); + return fold_convert (ptr_type_node, build_address (var)); + } + case CXA_FREE_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], true); + if (arg == NULL_TREE) + { + invalid_ptr: + if (!ctx->quiet) + error_at (loc, "first argument to %qD function not result of " + "%<__cxa_allocate_exception%>", fndecl); + *non_constant_p = true; + return call; + } + DECL_NAME (arg) = heap_deleted_identifier; + ctx->global->destroy_value (arg); + ctx->global->heap_dealloc_count++; + return void_node; + case CXA_THROW: + if (nargs != 3) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], false); + if (arg == NULL_TREE) + goto invalid_ptr; + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case CXA_BEGIN_CATCH: + case CXA_GET_EXCEPTION_PTR: + goto invalid_nargs; + case CXA_END_CATCH: + if (nargs != 0) + goto invalid_nargs; + if (ctx->global->caught_exceptions.is_empty ()) + { + no_active_exc: + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions active", + fndecl); + *non_constant_p = true; + return call; + } + else + { + arg = ctx->global->caught_exceptions.pop (); + if (arg == NULL_TREE || !VAR_P (arg)) + goto no_active_exc; + free_except: + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (MINUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + if (integer_zerop (DECL_EXCEPTION_REFCOUNT (arg))) + { + if (type_build_dtor_call (TREE_TYPE (arg))) + { + tree cleanup + = cxx_maybe_build_cleanup (arg, (ctx->quiet ? tf_none + : tf_warning_or_error)); + if (cleanup == error_mark_node) + *non_constant_p = true; + tree jmp_target = NULL_TREE; + cxx_eval_constant_expression (ctx, cleanup, vc_discard, + non_constant_p, overflow_p, + &jmp_target); + if (throws (&jmp_target)) + *jump_target = jmp_target; + } + DECL_NAME (arg) = heap_deleted_identifier; + ctx->global->destroy_value (arg); + ctx->global->heap_dealloc_count++; + } + } + return void_node; + case CXA_RETHROW: + if (nargs != 0) + goto invalid_nargs; + unsigned idx; + FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg) + if (arg == NULL_TREE || !VAR_P (arg)) + --idx; + else + break; + if (arg == NULL_TREE) + { + if (!ctx->quiet) + error_at (loc, "%qD called with no caught exceptions active", + fndecl); + *non_constant_p = true; + return call; + } + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case CXA_BAD_CAST: + case CXA_BAD_TYPEID: + case CXA_THROW_BAD_ARRAY_NEW_LENGTH: + if (nargs != 0) + goto invalid_nargs; + else + { + tree name; + switch (kind) + { + case CXA_BAD_CAST: + name = get_identifier ("bad_cast"); + break; + case CXA_BAD_TYPEID: + name = get_identifier ("bad_typeid"); + break; + case CXA_THROW_BAD_ARRAY_NEW_LENGTH: + name = get_identifier ("bad_array_new_length"); + break; + default: + gcc_unreachable (); + } + tree decl = lookup_qualified_name (std_node, name); + if (TREE_CODE (decl) != TYPE_DECL + || !CLASS_TYPE_P (TREE_TYPE (decl)) + || !type_build_ctor_call (TREE_TYPE (decl))) + { + if (!ctx->quiet) + error_at (loc, "%qD called without %<std::%D%> being defined", + fndecl, name); + *non_constant_p = true; + return call; + } + tree type = TREE_TYPE (decl); + tree var = cxa_allocate_exception (loc, ctx, type, size_one_node); + tree ctor + = build_special_member_call (var, complete_ctor_identifier, + NULL, type, LOOKUP_NORMAL, + ctx->quiet ? tf_none + : tf_warning_or_error); + if (ctor == error_mark_node) + { + *non_constant_p = true; + return call; + } + if (TREE_CONSTANT (ctor)) + ctx->global->put_value (var, ctor); + else + { + ctx->global->put_value (var, NULL_TREE); + cxx_eval_constant_expression (ctx, ctor, vc_discard, + non_constant_p, overflow_p, + jump_target); + if (*non_constant_p) + return call; + if (throws (jump_target)) + return NULL_TREE; + } + ++ctx->global->uncaught_exceptions; + *jump_target = var; + } + return void_node; + case STD_UNCAUGHT_EXCEPTIONS: + if (nargs != 0) + goto invalid_nargs; + /* Similarly to __builtin_is_constant_evaluated (), we don't + want to give a definite answer during mce_unknown evaluation, + because that might prevent evaluation later on when some + exceptions might be uncaught. But unlike that, we don't + want to constant fold it even during cp_fold, because at runtime + std::uncaught_exceptions () might still be non-zero. */ + if (ctx->manifestly_const_eval != mce_true) + { + *non_constant_p = true; + return call; + } + return build_int_cst (integer_type_node, + ctx->global->uncaught_exceptions); + case STD_CURRENT_EXCEPTION: + if (nargs != 0) + goto invalid_nargs; + else + { + tree name = get_identifier ("exception_ptr"); + tree decl = lookup_qualified_name (std_node, name); + tree fld; + if (TREE_CODE (decl) != TYPE_DECL + || !CLASS_TYPE_P (TREE_TYPE (decl)) + || !COMPLETE_TYPE_P (TREE_TYPE (decl)) + || !(fld = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (decl)))) + || DECL_ARTIFICIAL (fld) + || TREE_CODE (TREE_TYPE (fld)) != POINTER_TYPE + || next_aggregate_field (DECL_CHAIN (fld)) + || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (decl)), + TYPE_SIZE (TREE_TYPE (fld)))) + { + if (!ctx->quiet) + error_at (loc, "%qD called without supportable %qs", + fndecl, "std::exception_ptr"); + *non_constant_p = true; + return call; + } + FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg) + if (arg == NULL_TREE || !VAR_P (arg)) + --idx; + else + break; + /* Similarly to __builtin_is_constant_evaluated (), we don't + want to give a definite answer during mce_unknown evaluation, + because that might prevent evaluation later on when some + exceptions might be current. But unlike that, we don't + want to constant fold it to null even during cp_fold, because + at runtime std::current_exception () might still be non-null. */ + if (ctx->manifestly_const_eval != mce_true && arg == NULL_TREE) + { + *non_constant_p = true; + return call; + } + if (arg == NULL_TREE) + arg = build_zero_cst (TREE_TYPE (fld)); + else + { + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + arg = fold_convert (ptr_type_node, build_address (arg)); + } + return build_constructor_single (TREE_TYPE (decl), fld, arg); + } + case STD_RETHROW_EXCEPTION: + if (nargs != 1) + goto invalid_nargs; + if (TYPE_REF_P (TREE_TYPE (args[0]))) + { + arg = args[0]; + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR) + { + args[0] + = cxx_eval_constant_expression (ctx, TREE_OPERAND (arg, 0), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p) + return call; + if (*jump_target) + return NULL_TREE; + } + } + if (TREE_CODE (args[0]) != CONSTRUCTOR + || CONSTRUCTOR_NELTS (args[0]) != 1) + { + invalid_std_rethrow: + if (!ctx->quiet) + error_at (loc, "%qD called with unexpected %qs argument", + fndecl, "std::exception_ptr"); + *non_constant_p = true; + return void_node; + } + arg = cxa_check_throw_arg (CONSTRUCTOR_ELT (args[0], 0)->value, false); + if (arg == NULL_TREE) + goto invalid_std_rethrow; + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node); + ++ctx->global->uncaught_exceptions; + *jump_target = arg; + return void_node; + case BUILTIN_EH_PTR_ADJUST_REF: + if (nargs != 2) + goto invalid_nargs; + arg = cxa_check_throw_arg (args[0], false); + if (arg == NULL_TREE) + goto invalid_ptr; + if (integer_onep (args[1])) + DECL_EXCEPTION_REFCOUNT (arg) + = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), + size_one_node); + else if (integer_minus_onep (args[1])) + goto free_except; + else + { + if (!ctx->quiet) + error_at (loc, "%qD called with second argument " + "other than 1 or -1", fndecl); + *non_constant_p = true; + } + return void_node; + default: + gcc_unreachable (); + } +} /* Attempt to evaluate T which represents a call to a builtin function. We assume here that all builtin functions evaluate to scalar types @@ -1546,7 +2268,8 @@ static tree find_deleted_heap_var (tree *, int *, void *); static tree cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { const int nargs = call_expr_nargs (t); tree *args = (tree *) alloca (nargs * sizeof (tree)); @@ -1592,6 +2315,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, return fold_builtin_source_location (t); } + if (fndecl_built_in_p (fun, CP_BUILT_IN_EH_PTR_ADJUST_REF, + BUILT_IN_FRONTEND)) + return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_EH_PTR_ADJUST_REF, + fun, non_constant_p, overflow_p, + jump_target); + int strops = 0; int strret = 0; if (fndecl_built_in_p (fun, BUILT_IN_NORMAL)) @@ -1666,8 +2395,14 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, || potential_constant_expression (arg)) { bool dummy1 = false, dummy2 = false; + tree jmp_target = NULL_TREE; arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, - &dummy1, &dummy2); + &dummy1, &dummy2, &jmp_target); + if (jmp_target) + { + *jump_target = jmp_target; + return NULL_TREE; + } } if (bi_const_p) @@ -1756,7 +2491,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } return cxx_eval_constant_expression (&new_ctx, new_call, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* TEMP is the constant value of a temporary object of type TYPE. Adjust @@ -1870,20 +2606,29 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data) static tree cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, - bool *non_constant_p, bool *overflow_p, - bool *non_constant_args) + tree orig_fun, bool *non_constant_p, + bool *overflow_p, bool *non_constant_args, + tree *jump_target) { - const int nargs = call_expr_nargs (t); + int nargs = call_expr_nargs (t); tree parms = DECL_ARGUMENTS (fun); - int i; + int i, j = 0; + if (DECL_HAS_IN_CHARGE_PARM_P (fun) && fun != orig_fun) + ++nargs; + if (DECL_HAS_VTT_PARM_P (fun) + && fun != orig_fun + && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun) + || DECL_COMPLETE_DESTRUCTOR_P (orig_fun))) + ++nargs; /* We don't record ellipsis args below. */ int nparms = list_length (parms); int nbinds = nargs < nparms ? nargs : nparms; tree binds = make_tree_vec (nbinds); /* The call is not a constant expression if it involves the cdtor for a type - with virtual bases. */ - if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun)) + with virtual bases before C++26. */ + if (cxx_dialect < cxx26 + && (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))) { if (!ctx->quiet) { @@ -1901,7 +2646,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. */ @@ -1916,14 +2684,18 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Undo convert_for_arg_passing work here. */ x = convert_from_reference (x); arg = cxx_eval_constant_expression (ctx, x, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } else /* Normally we would strip a TARGET_EXPR in an initialization context such as this, but here we do the elision differently: we keep the TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + break; /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) @@ -2052,9 +2824,10 @@ fold_operand (tree e, const constexpr_ctx *ctx) if (ctx) { bool new_non_constant_p = false, new_overflow_p = false; + tree jmp_target = NULL_TREE; e = cxx_eval_constant_expression (ctx, e, vc_prvalue, &new_non_constant_p, - &new_overflow_p); + &new_overflow_p, &jmp_target); } else e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true); @@ -2113,10 +2886,15 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p, if (TREE_CODE (bad) == CLEANUP_POINT_EXPR) bad = TREE_OPERAND (bad, 0); + auto_diagnostic_nesting_level sentinel; + /* Actually explain the failure if this is a concept check or a requires-expression. */ if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR) diagnose_constraints (cloc, bad, NULL_TREE); + /* Similarly if this is a standard trait. */ + else if (maybe_diagnose_standard_trait (cloc, bad)) + ; else if (COMPARISON_CLASS_P (bad) && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0)))) { @@ -2141,7 +2919,7 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, if (*non_constant_p) return true; - tree eval; + tree eval, jmp_target = NULL_TREE; if (!evaluated) { if (!potential_rvalue_constant_expression (arg)) @@ -2154,12 +2932,15 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, modifiable_tracker ms (new_ctx.global); eval = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, &new_non_constant_p, - &new_overflow_p); + &new_overflow_p, &jmp_target); } else eval = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, &jmp_target); + if (jmp_target) + return true; + if (!*non_constant_p && integer_zerop (eval)) { if (!ctx->quiet) @@ -2191,7 +2972,8 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg, static tree cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { enum tree_code opcode = ERROR_MARK; @@ -2224,13 +3006,15 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, case IFN_LAUNDER: return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); case IFN_VEC_CONVERT: { tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (arg) == VECTOR_CST) if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg)) return r; @@ -2248,10 +3032,13 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, /* Evaluate constant arguments using OPCODE and return a complex number containing the result and the overflow bit. */ tree arg0 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); tree arg1 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 1), lval, - non_constant_p, overflow_p); - + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) { location_t loc = cp_expr_loc_or_input_loc (t); @@ -2453,7 +3240,11 @@ cxx_dynamic_cast_fn_p (tree fndecl) { return (cxx_dialect >= cxx20 && id_equal (DECL_NAME (fndecl), "__dynamic_cast") - && CP_DECL_CONTEXT (fndecl) == abi_node); + && CP_DECL_CONTEXT (fndecl) == abi_node + /* Only consider implementation-detail __dynamic_cast calls that + correspond to a dynamic_cast, and ignore direct calls to + abi::__dynamic_cast. */ + && DECL_ARTIFICIAL (fndecl)); } /* Often, we have an expression in the form of address + offset, e.g. @@ -2520,14 +3311,12 @@ get_component_with_type (tree path, tree type, tree stop) dst_ptr + src2dst == src_ptr -1: unspecified relationship -2: src_type is not a public base of dst_type - -3: src_type is a multiple public non-virtual base of dst_type - - Since literal types can't have virtual bases, we only expect hint >=0, - -2, or -3. */ + -3: src_type is a multiple public non-virtual base of dst_type */ static tree cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { /* T will be something like __dynamic_cast ((B*) b, &_ZTI1B, &_ZTI1D, 8) @@ -2546,19 +3335,42 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, /* TYPE can only be either T* or T&. We can't know which of these it is by looking at TYPE, but OBJ will be "(T*) x" in the first case, - and something like "(T*)(T&)(T*) x" in the second case. */ - bool reference_p = false; + and something like "(T*)(T&)(T*) x" in the second case. + This is true for the reference cases in C++ < 26 or when exceptions + aren't enabled, in that case we should diagnose errors. For C++26 + with exceptions we should silently evaluate to null pointer and + let the callers call __cxa_bad_cast () later to throw an exception. */ + bool fail_for_non_constant_p = false; while (CONVERT_EXPR_P (obj) || TREE_CODE (obj) == SAVE_EXPR) { - reference_p |= TYPE_REF_P (TREE_TYPE (obj)); + if (cxx_dialect < cxx26 || !flag_exceptions) + fail_for_non_constant_p |= TYPE_REF_P (TREE_TYPE (obj)); obj = TREE_OPERAND (obj, 0); } /* Evaluate the object so that we know its dynamic type. */ obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); if (*non_constant_p) return call; + if (*jump_target) + return NULL_TREE; + + /* For dynamic_cast from classes with virtual bases we can get something + like (virt_base *)(&d + 16) as OBJ. Try to convert that into + d.D.1234 using cxx_fold_indirect_ref. */ + if (cxx_dialect >= cxx26 && CONVERT_EXPR_P (obj)) + { + tree objo = obj; + STRIP_NOPS (objo); + if (TREE_CODE (objo) == POINTER_PLUS_EXPR) + { + objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)), + obj, NULL, jump_target); + if (objo) + obj = build_fold_addr_expr (objo); + } + } /* We expect OBJ to be in form of &d.D.2102 when HINT == 0, but when HINT is > 0, it can also be something like @@ -2570,7 +3382,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, ? TREE_OPERAND (obj, 1) : obj)) if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t)) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2592,9 +3404,12 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, constructor or destructor's class. */ tree vtable = build_vfield_ref (obj, objtype); vtable = cxx_eval_constant_expression (ctx, vtable, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return call; + if (*jump_target) + return NULL_TREE; /* With -fsanitize=vptr, we initialize all vtable pointers to null, so it's possible that we got a null pointer now. */ if (integer_zerop (vtable)) @@ -2626,7 +3441,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, /* If not accessible, give an error. */ if (t == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2659,7 +3474,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, obj = get_component_with_type (obj, mdtype, NULL_TREE); if (obj == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2681,7 +3496,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, tree binfo = lookup_base (mdtype, type, ba_check, &b_kind, tf_none); if (!binfo || binfo == error_mark_node) { - if (reference_p) + if (fail_for_non_constant_p) { if (!ctx->quiet) { @@ -2777,7 +3592,7 @@ replace_decl (tree *tp, tree decl, tree replacement) static tree cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree function = THUNK_TARGET (thunk_fndecl); @@ -2820,7 +3635,8 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, new_call, offset); return cxx_eval_constant_expression (ctx, new_call, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* If OBJECT is of const class type, evaluate it to a CONSTRUCTOR and set @@ -2830,7 +3646,7 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, static void cxx_set_object_constness (const constexpr_ctx *ctx, tree object, bool readonly_p, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { if (CLASS_TYPE_P (TREE_TYPE (object)) && CP_TYPE_CONST_P (TREE_TYPE (object))) @@ -2838,8 +3654,11 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, /* Subobjects might not be stored in ctx->global->values but we can get its CONSTRUCTOR by evaluating *this. */ tree e = cxx_eval_constant_expression (ctx, object, vc_prvalue, - non_constant_p, overflow_p); - if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p) + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p + && !throws (jump_target) + && TREE_CODE (e) == CONSTRUCTOR) TREE_READONLY (e) = readonly_p; } } @@ -2851,23 +3670,25 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, static tree cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { location_t loc = cp_expr_loc_or_input_loc (t); tree fun = get_function_named_in_call (t); - constexpr_call new_call - = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval }; - int depth_ok; if (fun == NULL_TREE) return cxx_eval_internal_function (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ fun = cxx_eval_constant_expression (ctx, fun, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; STRIP_NOPS (fun); if (TREE_CODE (fun) == ADDR_EXPR) fun = TREE_OPERAND (fun, 0); @@ -2910,6 +3731,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); @@ -2918,9 +3740,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, if (fndecl_built_in_p (fun)) return cxx_eval_builtin_function_call (ctx, t, fun, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); if (DECL_THUNK_P (fun)) - return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p); + return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p, + jump_target); + bool non_constexpr_call = false; if (!maybe_constexpr_fn (fun)) { if (TREE_CODE (t) == CALL_EXPR @@ -2935,7 +3760,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { tree arg = CALL_EXPR_ARG (t, i); arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Deleting a non-constant pointer has a better error message below. */ if (new_op_p || i != 0) @@ -2946,12 +3774,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 +3793,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)); @@ -3059,7 +3878,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { tree arg = CALL_EXPR_ARG (t, i); arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (i == 1) arg1 = arg; else @@ -3069,19 +3891,35 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, return arg1; } else if (cxx_dynamic_cast_fn_p (fun)) - return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p); + return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p, + jump_target); + else if (enum cxa_builtin kind = cxx_cxa_builtin_fn_p (fun)) + return cxx_eval_cxa_builtin_fn (ctx, t, kind, fun, + non_constant_p, overflow_p, + jump_target); - if (!ctx->quiet) + /* Calls to non-constexpr functions can be diagnosed right away + before C++26, though in C++26 evaluation of the arguments might + throw and if caught it could be still constant expression. + So for C++26 this is diagnosed only after + cxx_bind_parameters_in_call. */ + if (cxx_dialect >= cxx26) + non_constexpr_call = true; + else { - if (!lambda_static_thunk_p (fun)) - error_at (loc, "call to non-%<constexpr%> function %qD", fun); - explain_invalid_constexpr_fn (fun); + if (!ctx->quiet) + { + if (!lambda_static_thunk_p (fun)) + error_at (loc, "call to non-%<constexpr%> function %qD", fun); + explain_invalid_constexpr_fn (fun); + } + *non_constant_p = true; + return t; } - *non_constant_p = true; - return t; } constexpr_ctx new_ctx = *ctx; + ctx = &new_ctx; if (DECL_CONSTRUCTOR_P (fun) && !ctx->object && TREE_CODE (t) == AGGR_INIT_EXPR) { @@ -3091,30 +3929,30 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL); CONSTRUCTOR_NO_CLEARING (ctor) = true; ctx->global->put_value (new_ctx.object, ctor); - ctx = &new_ctx; } /* An immediate invocation is manifestly constant evaluated including the arguments of the call, so use mce_true even for the argument evaluation. */ if (DECL_IMMEDIATE_FUNCTION_P (fun)) - { - new_ctx.manifestly_const_eval = mce_true; - new_call.manifestly_const_eval = mce_true; - ctx = &new_ctx; - } + new_ctx.manifestly_const_eval = mce_true; /* We used to shortcut trivial constructor/op= here, but nowadays we can only get a trivial function here with -fno-elide-constructors. */ gcc_checking_assert (!trivial_fn_p (fun) || !flag_elide_constructors + /* Or it's a call from maybe_thunk_body (111075). */ + || (TREE_CODE (t) == CALL_EXPR ? CALL_FROM_THUNK_P (t) + : AGGR_INIT_FROM_THUNK_P (t)) /* We don't elide constructors when processing a noexcept-expression. */ || cp_noexcept_operand); bool non_constant_args = false; + constexpr_call new_call; new_call.bindings - = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p, - overflow_p, &non_constant_args); + = cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p, + overflow_p, &non_constant_args, + jump_target); /* We build up the bindings list before we know whether we already have this call cached. If we don't end up saving these bindings, ggc_free them when @@ -3128,8 +3966,21 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, void preserve () { bindings = NULL; } } fb (new_call.bindings); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; + if (non_constexpr_call) + { + if (!ctx->quiet) + { + if (!lambda_static_thunk_p (fun)) + error_at (loc, "call to non-%<constexpr%> function %qD", fun); + explain_invalid_constexpr_fn (fun); + } + *non_constant_p = true; + return t; + } /* We can't defer instantiating the function any longer. */ if (!DECL_INITIAL (fun) @@ -3185,7 +4036,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; @@ -3197,7 +4053,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_obj = TREE_VEC_ELT (new_call.bindings, 0); bool empty_base = false; new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj, - &empty_base); + &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; /* If we're initializing an empty class, don't set constness, because cxx_fold_indirect_ref will return the wrong object to set constness of. */ @@ -3227,8 +4085,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 +4102,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) @@ -3347,7 +4204,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, semantics are no longer in effect; see [class.dtor]p5. */ if (new_obj && DECL_DESTRUCTOR_P (fun)) cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/false, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); /* If this is a constructor, we are beginning the lifetime of the object we are initializing. */ @@ -3356,21 +4213,30 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, && TREE_CODE (new_obj) == COMPONENT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == UNION_TYPE) { + tree ctor = build_constructor (TREE_TYPE (new_obj), NULL); + CONSTRUCTOR_NO_CLEARING (ctor) = true; tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj), - new_obj, - build_constructor (TREE_TYPE (new_obj), - NULL)); + new_obj, ctor); cxx_eval_constant_expression (ctx, activate, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); ggc_free (activate); + if (*jump_target) + return NULL_TREE; } - tree jump_target = NULL_TREE; + tree jmp_target = NULL_TREE; cxx_eval_constant_expression (&call_ctx, body, vc_discard, non_constant_p, overflow_p, - &jump_target); + &jmp_target); - if (DECL_CONSTRUCTOR_P (fun)) + if (!*non_constant_p && throws (&jmp_target)) + { + result = NULL_TREE; + cacheable = false; + *jump_target = jmp_target; + } + else if (DECL_CONSTRUCTOR_P (fun)) /* This can be null for a subobject constructor call, in which case what we care about is the initialization side-effects rather than the value. We could get at the @@ -3398,7 +4264,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, marking the CONSTRUCTOR TREE_READONLY. */ if (new_obj && DECL_CONSTRUCTOR_P (fun)) cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/true, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); /* Remove the parms/result from the values map. */ destroy_value_checked (ctx, res, non_constant_p); @@ -3441,11 +4307,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 @@ -3463,7 +4324,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cacheable = false; result = cxx_eval_constant_expression (ctx, result, lval, non_constant_p, - overflow_p); + overflow_p, + jump_target); + if (*jump_target) + { + cacheable = false; + result = NULL_TREE; + } } } @@ -3482,7 +4349,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 +4385,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 +4401,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 +4458,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 +4483,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. */ @@ -3788,12 +4688,16 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx, static tree cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r; tree orig_arg = TREE_OPERAND (t, 0); tree arg = cxx_eval_constant_expression (ctx, orig_arg, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg); location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); @@ -3817,7 +4721,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, static tree cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, tree lhs, tree rhs, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { STRIP_NOPS (lhs); if (TREE_CODE (lhs) != ADDR_EXPR) @@ -3839,9 +4743,12 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1)); tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0))); nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return NULL_TREE; + if (*jump_target) + return NULL_TREE; /* Don't fold an out-of-bound access. */ if (!tree_int_cst_le (t, nelts)) return NULL_TREE; @@ -3861,7 +4768,8 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t = cp_build_addr_expr (t, tf_warning_or_error); t = cp_fold_convert (orig_type, t); return cxx_eval_constant_expression (ctx, t, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } return NULL_TREE; @@ -3905,22 +4813,29 @@ cxx_maybe_fold_addr_pointer_plus (tree t) static tree cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r = NULL_TREE; tree orig_lhs = TREE_OPERAND (t, 0); tree orig_rhs = TREE_OPERAND (t, 1); tree lhs, rhs; lhs = cxx_eval_constant_expression (ctx, orig_lhs, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer subtraction. */ if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; rhs = cxx_eval_constant_expression (ctx, orig_rhs, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; location_t loc = EXPR_LOCATION (t); enum tree_code code = TREE_CODE (t); @@ -3976,13 +4891,17 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, return t; } else if (code == POINTER_PLUS_EXPR) - r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p, - overflow_p); + { + r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p, + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; + } else if (code == SPACESHIP_EXPR) { r = genericize_spaceship (loc, type, lhs, rhs); return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } if (r == NULL_TREE) @@ -4041,7 +4960,10 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, { tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (val); if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) { @@ -4102,19 +5024,29 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg1); tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg2); tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (arg3); location_t loc = EXPR_LOCATION (t); tree type = TREE_TYPE (t); @@ -4502,7 +5434,8 @@ diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array, tree static tree get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree nelts; if (TREE_CODE (type) == ARRAY_TYPE) @@ -4519,7 +5452,8 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type, /* For VLAs, the number of elements won't be an integer constant. */ nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); return nelts; } @@ -4550,13 +5484,17 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index) static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t, bool allow_one_past, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { location_t loc = cp_expr_loc_or_input_loc (t); tree ary = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 1); tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (index); if (!tree_fits_shwi_p (index) @@ -4568,7 +5506,9 @@ eval_and_check_array_index (const constexpr_ctx *ctx, } tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (nelts); if (allow_one_past ? !tree_int_cst_le (index, nelts) @@ -4588,14 +5528,18 @@ eval_and_check_array_index (const constexpr_ctx *ctx, static tree cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree oldary = TREE_OPERAND (t, 0); tree ary = cxx_eval_constant_expression (ctx, oldary, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (!lval && TREE_CODE (ary) == VIEW_CONVERT_EXPR && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0))) @@ -4605,9 +5549,12 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, tree oldidx = TREE_OPERAND (t, 1); tree index = eval_and_check_array_index (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (lval && ary == oldary && index == oldidx) return t; @@ -4725,7 +5672,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ctx = &new_ctx; } t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); if (new_ctor && t != ctx->ctor) free_constructor (ctx->ctor); return t; @@ -4737,7 +5684,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { unsigned HOST_WIDE_INT i; tree field; @@ -4746,9 +5694,12 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, tree orig_whole = TREE_OPERAND (t, 0); tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0))) { @@ -4854,10 +5805,23 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, } /* If there's no explicit init for this field, it's value-initialized. */ + + if (AGGREGATE_TYPE_P (TREE_TYPE (t))) + { + /* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR + and copy the flags. */ + constructor_elt *e = get_or_insert_ctor_field (whole, part); + e->value = value = build_constructor (TREE_TYPE (part), NULL); + CONSTRUCTOR_ZERO_PADDING_BITS (value) + = CONSTRUCTOR_ZERO_PADDING_BITS (whole); + return value; + } + value = build_value_init (TREE_TYPE (t), tf_warning_or_error); return cxx_eval_constant_expression (ctx, value, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* Subroutine of cxx_eval_constant_expression. @@ -4867,7 +5831,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree orig_whole = TREE_OPERAND (t, 0); tree retval, fldval, utype, mask; @@ -4875,10 +5840,13 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, HOST_WIDE_INT istart, isize; tree whole = cxx_eval_constant_expression (ctx, orig_whole, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); tree start, field, value; unsigned HOST_WIDE_INT i; + if (*jump_target) + return NULL_TREE; if (whole == orig_whole) return t; /* Don't VERIFY_CONSTANT here; we only want to check that we got a @@ -5159,7 +6127,7 @@ clear_uchar_or_std_byte_in_mask (location_t loc, tree t, unsigned char *mask) static tree cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p) + bool *overflow_p, tree *jump_target) { if (check_bit_cast_type (ctx, EXPR_LOCATION (t), TREE_TYPE (t), TREE_TYPE (t)) @@ -5173,9 +6141,12 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, } tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) return t; + if (*jump_target) + return NULL_TREE; location_t loc = EXPR_LOCATION (t); if (BITS_PER_UNIT != 8 || CHAR_BIT != 8) @@ -5253,8 +6224,9 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, if (CHECKING_P) { tree e = cxx_eval_bare_aggregate (ctx, r, vc_prvalue, - non_constant_p, overflow_p); - gcc_checking_assert (e == r); + non_constant_p, overflow_p, + jump_target); + gcc_checking_assert (e == r && !*jump_target); r = e; } } @@ -5295,19 +6267,24 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, static tree cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t, tree bailout_value, tree continue_value, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree r; tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (lhs); if (tree_int_cst_equal (lhs, bailout_value)) return lhs; gcc_assert (tree_int_cst_equal (lhs, continue_value)); r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (r); return r; } @@ -5464,7 +6441,8 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type) static tree cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); bool changed = false; @@ -5517,7 +6495,10 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, get_or_insert_ctor_field (ctx->ctor, index); tree elt = cxx_eval_constant_expression (&new_ctx, value, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (ctx->quiet && *non_constant_p) break; @@ -5607,7 +6588,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, static tree cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, bool value_init, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree elttype = TREE_TYPE (atype); verify_ctor_sanity (ctx, atype); @@ -5618,7 +6600,10 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, if (init && TREE_CODE (init) == CONSTRUCTOR) return cxx_eval_bare_aggregate (ctx, init, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); + + /* We already checked access when building the VEC_INIT_EXPR. */ + deferring_access_check_sentinel acs (dk_deferred); /* For the default constructor, build up a call to the default constructor of the element type. We only need to handle class types @@ -5655,7 +6640,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, } tree nelts = get_array_or_vector_nelts (ctx, atype, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; unsigned HOST_WIDE_INT max = tree_to_uhwi (nelts); for (i = 0; i < max; ++i) { @@ -5681,9 +6668,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, } else eltinit = cp_build_array_ref (input_location, init, idx, complain); - eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init, - lval, - non_constant_p, overflow_p); + eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, + value_init, lval, non_constant_p, + overflow_p, jump_target); } else if (pre_init) { @@ -5697,7 +6684,8 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, /* Clarify what object is being initialized (118285). */ eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit); eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); reuse = i == 0; } else @@ -5713,8 +6701,11 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, /* Clarify what object is being initialized (118285). */ eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit); eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } + if (*jump_target) + return NULL_TREE; if (*non_constant_p) break; if (no_slot) @@ -5764,7 +6755,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, static tree cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree atype = TREE_TYPE (t); tree init = VEC_INIT_EXPR_INIT (t); @@ -5796,10 +6787,10 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, } init = expand_vec_init_expr (ctx->object, t, complain); return cxx_eval_constant_expression (ctx, init, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } tree r = cxx_eval_vec_init_1 (ctx, atype, init, value_init, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, jump_target); if (*non_constant_p) return t; else @@ -5828,14 +6819,16 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) otherwise return NULL_TREE. */ static tree -cxx_union_active_member (const constexpr_ctx *ctx, tree t) +cxx_union_active_member (const constexpr_ctx *ctx, tree t, tree *jump_target) { constexpr_ctx new_ctx = *ctx; new_ctx.quiet = true; bool non_constant_p = false, overflow_p = false; tree ctor = cxx_eval_constant_expression (&new_ctx, t, vc_prvalue, &non_constant_p, - &overflow_p); + &overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (TREE_CODE (ctor) == CONSTRUCTOR && CONSTRUCTOR_NELTS (ctor) == 1 && CONSTRUCTOR_ELT (ctor, 0)->index @@ -5848,12 +6841,28 @@ cxx_union_active_member (const constexpr_ctx *ctx, tree t) static tree cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, - tree op, unsigned HOST_WIDE_INT off, bool *empty_base) + tree op, unsigned HOST_WIDE_INT off, bool *empty_base, + tree *jump_target) { tree optype = TREE_TYPE (op); unsigned HOST_WIDE_INT const_nunits; if (off == 0 && similar_type_p (optype, type)) return op; + else if (cxx_dialect >= cxx26 + && VAR_P (op) + && DECL_VTABLE_OR_VTT_P (op) + && same_type_ignoring_top_level_qualifiers_p (type, + ptrdiff_type_node) + && POINTER_TYPE_P (strip_array_types (optype))) + { + /* We often read some virtual table elements using ptrdiff_t rather + than pointer type. */ + if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, + strip_array_types (optype), + op, off, empty_base, + jump_target)) + return fold_convert (type, ret); + } else if (TREE_CODE (optype) == COMPLEX_TYPE && similar_type_p (type, TREE_TYPE (optype))) { @@ -5897,7 +6906,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index, NULL_TREE, NULL_TREE); return cxx_fold_indirect_ref_1 (ctx, loc, type, op, rem, - empty_base); + empty_base, jump_target); } } /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */ @@ -5906,7 +6915,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, { if (TREE_CODE (optype) == UNION_TYPE) /* For unions prefer the currently active member. */ - if (tree field = cxx_union_active_member (ctx, op)) + if (tree field = cxx_union_active_member (ctx, op, jump_target)) { unsigned HOST_WIDE_INT el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); @@ -5915,7 +6924,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), op, field, NULL_TREE); if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop, - off, empty_base)) + off, empty_base, + jump_target)) return ret; } } @@ -5947,15 +6957,21 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, if (!tree_fits_uhwi_p (pos)) continue; unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos); - unsigned HOST_WIDE_INT el_sz - = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); + unsigned HOST_WIDE_INT el_sz; + if (DECL_FIELD_IS_BASE (field) + && CLASS_TYPE_P (optype) + && CLASSTYPE_VBASECLASSES (optype)) + el_sz = tree_to_uhwi (DECL_SIZE_UNIT (field)); + else + el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); if (upos <= off && off < upos + el_sz) { tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), op, field, NULL_TREE); if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop, off - upos, - empty_base)) + empty_base, + jump_target)) return ret; } } @@ -5975,7 +6991,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, - tree op0, bool *empty_base /* = NULL*/) + tree op0, bool *empty_base, tree *jump_target) { tree sub = op0; tree subtype; @@ -5999,6 +7015,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 +7072,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, { tree off = integer_zero_node; canonicalize_obj_off (op, off); - gcc_assert (integer_zerop (off)); - return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base); + return cxx_fold_indirect_ref_1 (ctx, loc, type, op, + tree_to_uhwi (off), empty_base, + jump_target); } } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR @@ -6053,7 +7089,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, tree obj = TREE_OPERAND (op00, 0); canonicalize_obj_off (obj, off); return cxx_fold_indirect_ref_1 (ctx, loc, type, obj, - tree_to_uhwi (off), empty_base); + tree_to_uhwi (off), empty_base, + jump_target); } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ @@ -6063,7 +7100,10 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, tree type_domain; tree min_val = size_zero_node; tree newsub - = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL); + = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL, + jump_target); + if (*jump_target) + return NULL_TREE; if (newsub) sub = newsub; else @@ -6081,7 +7121,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { tree orig_op0 = TREE_OPERAND (t, 0); bool empty_base = false; @@ -6099,13 +7140,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, /* First try to simplify it directly. */ tree r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), - orig_op0, &empty_base); + orig_op0, &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; if (!r) { /* If that didn't work, evaluate the operand first. */ tree op0 = cxx_eval_constant_expression (ctx, orig_op0, vc_prvalue, non_constant_p, - overflow_p); + overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; @@ -6119,7 +7164,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, } r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), op0, - &empty_base); + &empty_base, jump_target); + if (*jump_target) + return NULL_TREE; if (r == NULL_TREE) { /* We couldn't fold to a constant value. Make sure it's not @@ -6132,10 +7179,23 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), - "accessing value of %qE through a %qT glvalue in a " - "constant expression", build_fold_indirect_ref (sub), - TREE_TYPE (t)); + { + auto_diagnostic_group d; + error_at (cp_expr_loc_or_input_loc (t), + "accessing value of %qT object through a %qT " + "glvalue in a constant expression", + TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)); + tree ob = build_fold_indirect_ref (sub); + if (DECL_P (ob)) + { + if (DECL_ARTIFICIAL (ob)) + inform (DECL_SOURCE_LOCATION (ob), + "%qT object created here", TREE_TYPE (ob)); + else + inform (DECL_SOURCE_LOCATION (ob), + "%q#D declared here", ob); + } + } *non_constant_p = true; return t; } @@ -6149,7 +7209,10 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, } r = cxx_eval_constant_expression (ctx, r, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; @@ -6259,7 +7322,8 @@ non_const_var_error (location_t loc, tree r, bool fundef_p) static tree cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { int i; tree args[3]; @@ -6269,7 +7333,10 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, { args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (args[i]); } @@ -6391,17 +7458,13 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p) static tree cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { constexpr_ctx new_ctx = *ctx; tree init = TREE_OPERAND (t, 1); - if (TREE_CLOBBER_P (init) - && CLOBBER_KIND (init) < CLOBBER_OBJECT_END) - /* Only handle clobbers ending the lifetime of objects. */ - return void_node; - /* First we figure out where we're storing to. */ tree target = TREE_OPERAND (t, 0); @@ -6416,7 +7479,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (!SCALAR_TYPE_P (type)) new_ctx.ctor = new_ctx.object = NULL_TREE; init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6428,8 +7494,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, as a whole; otherwise, only evaluate the innermost piece to avoid building up unnecessary *_REFs. */ target = cxx_eval_constant_expression (ctx, target, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); evaluated = true; + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6455,7 +7524,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (probe) == ARRAY_REF) { elt = eval_and_check_array_index (ctx, probe, false, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6512,8 +7584,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, break; } probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); evaluated = true; + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; } @@ -6576,11 +7651,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, } /* Handle explicit end-of-lifetime. */ - if (TREE_CLOBBER_P (init)) + if (TREE_CLOBBER_P (init) + && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END) { if (refs->is_empty ()) - ctx->global->destroy_value (object); - return void_node; + { + ctx->global->destroy_value (object); + return void_node; + } + + /* Ending the lifetime of a const object is OK. */ + const_object_being_modified = NULL_TREE; } type = TREE_TYPE (object); @@ -6683,13 +7764,24 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (*valp), first, NULL_TREE); /* Check for implicit change of active member for a union. */ + + /* LWG3436, CWG2675, c++/121068: The array object model is confused. For + now allow initializing an array element to activate the array. */ + auto only_array_refs = [](const releasing_vec &refs) + { + for (unsigned i = 1; i < refs->length(); i += 3) + if (TREE_CODE ((*refs)[i]) != INTEGER_CST) + return false; + return true; + }; + if (code == UNION_TYPE && (CONSTRUCTOR_NELTS (*valp) == 0 || CONSTRUCTOR_ELT (*valp, 0)->index != index) /* An INIT_EXPR of the last member in an access chain is always OK, but still check implicit change of members earlier on; see cpp2a/constexpr-union6.C. */ - && !(TREE_CODE (t) == INIT_EXPR && refs->is_empty ())) + && !(TREE_CODE (t) == INIT_EXPR && only_array_refs (refs))) { bool has_active_member = CONSTRUCTOR_NELTS (*valp) != 0; tree inner = strip_array_types (reftype); @@ -6706,6 +7798,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; } else if (!is_access_expr + || (TREE_CLOBBER_P (init) + && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END) || (TREE_CODE (t) == MODIFY_EXPR && CLASS_TYPE_P (inner) && !type_has_non_deleted_trivial_default_ctor (inner))) @@ -6769,11 +7863,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, type = reftype; } + /* Change an "as-base" clobber to the real type; + we don't need to worry about padding in constexpr. */ + tree itype = initialized_type (init); + if (IS_FAKE_BASE_TYPE (itype)) + itype = TYPE_CONTEXT (itype); + /* For initialization of an empty base, the original target will be *(base*)this, evaluation of which resolves to the object argument, which has the derived type rather than the base type. */ if (!empty_base && !(same_type_ignoring_top_level_qualifiers_p - (initialized_type (init), type))) + (itype, type))) { gcc_assert (is_empty_class (TREE_TYPE (target))); empty_base = true; @@ -6857,7 +7957,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (tree tinit = TARGET_EXPR_INITIAL (init)) init = tinit; init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* The hash table might have moved since the get earlier, and the initializer might have mutated the underlying CONSTRUCTORs, so we must recompute VALP. */ @@ -6877,8 +7980,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* Don't share a CONSTRUCTOR that might be changed later. */ init = unshare_constructor (init); - gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (*valp), type))); + gcc_checking_assert (!*valp + || *valp == void_node + || (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (*valp), type))); if (empty_base) { /* Just evaluate the initializer and return, since there's no actual data @@ -6891,6 +7996,22 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits; } } + else if (TREE_CLOBBER_P (init)) + { + if (AGGREGATE_TYPE_P (type)) + { + if (*valp) + CONSTRUCTOR_ELTS (*valp) = nullptr; + else + *valp = build_constructor (type, nullptr); + TREE_CONSTANT (*valp) = true; + TREE_SIDE_EFFECTS (*valp) = false; + CONSTRUCTOR_NO_CLEARING (*valp) = true; + CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits; + } + else + *valp = void_node; + } else if (*valp && TREE_CODE (*valp) == CONSTRUCTOR && TREE_CODE (init) == CONSTRUCTOR) { @@ -6915,6 +8036,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, && TREE_CODE (*valp) == CONSTRUCTOR && TYPE_READONLY (type)) { + tree target_type = TREE_TYPE (target); + if (IS_FAKE_BASE_TYPE (target_type)) + target_type = TYPE_CONTEXT (target_type); if (INDIRECT_REF_P (target) && (is_this_parameter (tree_strip_nop_conversions (TREE_OPERAND (target, 0))))) @@ -6922,7 +8046,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, constructor of a delegating constructor). Leave it up to the caller that set 'this' to set TREE_READONLY appropriately. */ gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (target), type) || empty_base); + (target_type, type) || empty_base); else TREE_READONLY (*valp) = true; } @@ -6983,7 +8107,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, value_cat lval, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { enum tree_code code = TREE_CODE (t); tree type = TREE_TYPE (t); @@ -6997,12 +8122,18 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, /* The operand as an lvalue. */ op = cxx_eval_constant_expression (ctx, op, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* The operand as an rvalue. */ tree val = cxx_eval_constant_expression (ctx, op, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to a local array in a constexpr function. */ bool ptr = INDIRECT_TYPE_P (TREE_TYPE (val)); @@ -7041,8 +8172,11 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, tree store = build2_loc (cp_expr_loc_or_loc (t, input_location), MODIFY_EXPR, type, op, mod); mod = cxx_eval_constant_expression (ctx, store, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); ggc_free (store); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; @@ -7056,42 +8190,6 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, return val; } -/* Predicates for the meaning of *jump_target. */ - -static bool -returns (tree *jump_target) -{ - return *jump_target - && TREE_CODE (*jump_target) == RETURN_EXPR; -} - -static bool -breaks (tree *jump_target) -{ - return *jump_target - && ((TREE_CODE (*jump_target) == LABEL_DECL - && LABEL_DECL_BREAK (*jump_target)) - || TREE_CODE (*jump_target) == BREAK_STMT - || TREE_CODE (*jump_target) == EXIT_EXPR); -} - -static bool -continues (tree *jump_target) -{ - return *jump_target - && ((TREE_CODE (*jump_target) == LABEL_DECL - && LABEL_DECL_CONTINUE (*jump_target)) - || TREE_CODE (*jump_target) == CONTINUE_STMT); - -} - -static bool -switches (tree *jump_target) -{ - return *jump_target - && TREE_CODE (*jump_target) == INTEGER_CST; -} - /* Subroutine of cxx_eval_statement_list. Determine whether the statement STMT matches *jump_target. If we're looking for a case label and we see the default label, note it in ctx->css_state. */ @@ -7139,6 +8237,11 @@ label_matches (const constexpr_ctx *ctx, tree *jump_target, tree stmt) breaks (jump_target) or continues (jump_target). */ break; + case VAR_DECL: + /* Uncaught exception. This is handled by TRY_BLOCK evaluation + and other places by testing throws (jump_target). */ + break; + default: gcc_unreachable (); } @@ -7153,15 +8256,9 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree local_target; /* In a statement-expression we want to return the last value. For empty statement expression return void_node. */ tree r = void_node; - if (!jump_target) - { - local_target = NULL_TREE; - jump_target = &local_target; - } for (tree_stmt_iterator i = tsi_start (t); !tsi_end_p (i); ++i) { tree stmt = *i; @@ -7189,18 +8286,11 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, jump_target); if (*non_constant_p) break; - if (returns (jump_target) || breaks (jump_target)) + if (returns (jump_target) + || breaks (jump_target) + || throws (jump_target)) break; } - if (*jump_target && jump_target == &local_target) - { - /* We aren't communicating the jump to our caller, so give up. We don't - need to support evaluation of jumps out of statement-exprs. */ - if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (r), - "statement is not a constant expression"); - *non_constant_p = true; - } return r; } @@ -7212,13 +8302,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree local_target; - if (!jump_target) - { - local_target = NULL_TREE; - jump_target = &local_target; - } - tree body, cond = NULL_TREE, expr = NULL_TREE; tree cond_prep = NULL_TREE, cond_cleanup = NULL_TREE; unsigned cond_cleanup_depth = 0; @@ -7274,7 +8357,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, tree c; FOR_EACH_VEC_ELT_REVERSE (cleanups, i, c) cxx_eval_constant_expression (ctx, c, vc_discard, non_constant_p, - overflow_p); + overflow_p, jump_target); } if (cond_prep) for (tree decl = BIND_EXPR_VARS (cond_prep); @@ -7369,7 +8452,8 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (*non_constant_p || returns (jump_target) || breaks (jump_target) - || continues (jump_target)) + || continues (jump_target) + || throws (jump_target)) { depth = 1; break; @@ -7416,6 +8500,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, && !breaks (jump_target) && !continues (jump_target) && (!switches (jump_target) || count == 0) + && !throws (jump_target) && !*non_constant_p); cleanup_cond (); @@ -7434,7 +8519,10 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, tree cond = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t); cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (cond); if (TREE_CODE (cond) != INTEGER_CST) { @@ -7567,7 +8655,8 @@ maybe_warn_about_constant_value (location_t loc, tree decl) static tree build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, tree cookie_size, tree full_size, tree arg_size, - bool *non_constant_p, bool *overflow_p) + bool *non_constant_p, bool *overflow_p, + tree *jump_target) { gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size)); gcc_assert (tree_fits_uhwi_p (full_size)); @@ -7603,13 +8692,17 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, if (integer_zerop (op0)) arg_size = cxx_eval_constant_expression (ctx, op1, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); else if (integer_zerop (op1)) arg_size = cxx_eval_constant_expression (ctx, op0, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); else arg_size = NULL_TREE; + if (*jump_target) + return NULL_TREE; } else arg_size = NULL_TREE; @@ -7630,6 +8723,38 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, return build_new_constexpr_heap_type (elt_type, cookie_size, itype2); } +/* Handle the case when a cleanup of some expression throws. JMP_TARGET + indicates whether the cleanup threw or not, *JUMP_TARGET indicates whether + the expression which needed the cleanup threw. If both threw, diagnose + it and return NULL, otherwise return R. If only the cleanup threw, set + *JUMP_TARGET to the exception object from the cleanup. */ + +static tree +merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r, + bool *non_constant_p, tree *jump_target, tree jmp_target) +{ + if (!throws (&jmp_target)) + return r; + if (throws (jump_target)) + { + /* [except.throw]/9 - If the exception handling mechanism + handling an uncaught exception directly invokes a function + that exits via an exception, the function std::terminate is + invoked. */ + if (!ctx->quiet) + { + auto_diagnostic_group d; + diagnose_std_terminate (loc, ctx, *jump_target); + inform (loc, "destructor exited with an exception"); + } + *non_constant_p = true; + *jump_target = NULL_TREE; + return NULL_TREE; + } + *jump_target = jmp_target; + return r; +} + /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ @@ -7639,9 +8764,9 @@ static tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, value_cat lval, bool *non_constant_p, bool *overflow_p, - tree *jump_target /* = NULL */) + tree *jump_target) { - if (jump_target && *jump_target) + if (*jump_target) { /* If we are jumping, ignore all statements/expressions except those that could have LABEL_EXPR or CASE_LABEL_EXPR in their bodies. */ @@ -7765,7 +8890,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = convert_from_reference (r); } return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, - overflow_p); + overflow_p, jump_target); } /* fall through */ case CONST_DECL: @@ -7827,6 +8952,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: @@ -7842,7 +8968,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = v; if (TREE_ADDRESSABLE (TREE_TYPE (t))) r = cxx_eval_constant_expression (ctx, r, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; } else if (lval) /* Defer in case this is only used for its type. */; @@ -7875,7 +9004,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case CALL_EXPR: case AGGR_INIT_EXPR: r = cxx_eval_call_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case DECL_EXPR: @@ -7939,7 +9068,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (tree init = DECL_INITIAL (r)) { init = cxx_eval_constant_expression (ctx, init, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't share a CONSTRUCTOR that might be changed. */ init = unshare_constructor (init); /* Remember that a constant object's constructor has already @@ -7998,14 +9130,23 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ctx->global->put_value (new_ctx.object, new_ctx.ctor); ctx = &new_ctx; } + + /* If the initializer is complex, evaluate it to initialize slot. */ + bool is_complex = target_expr_needs_replace (t); + if (is_complex) + /* In case no initialization actually happens, clear out any + void_node from a previous evaluation. */ + ctx->global->put_value (slot, NULL_TREE); + /* Pass vc_prvalue because this indicates initialization of a temporary. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); if (*non_constant_p) break; - /* If the initializer is complex, evaluate it to initialize slot. */ - bool is_complex = target_expr_needs_replace (t); + if (*jump_target) + return NULL_TREE; if (!is_complex) { r = unshare_constructor (r); @@ -8013,8 +9154,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = adjust_temp_type (type, r); ctx->global->put_value (slot, r); } - if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t)) - ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t)); + if (TARGET_EXPR_CLEANUP (t) + && (!CLEANUP_EH_ONLY (t) || cxx_dialect >= cxx26)) + { + ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t)); + /* Mark CLEANUP_EH_ONLY cleanups by pushing NULL_TREE after + them. */ + if (CLEANUP_EH_ONLY (t)) + ctx->global->cleanups->safe_push (NULL_TREE); + } if (ctx->save_exprs) ctx->save_exprs->safe_push (slot); if (lval) @@ -8028,33 +9176,28 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case MODIFY_EXPR: gcc_assert (jump_target == NULL || *jump_target == NULL_TREE); r = cxx_eval_store_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case SCOPE_REF: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case RETURN_EXPR: if (TREE_OPERAND (t, 0) != NULL_TREE) r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); - /* FALLTHRU */ + non_constant_p, overflow_p, + jump_target); + if (!throws (jump_target)) + *jump_target = t; + break; case BREAK_STMT: case CONTINUE_STMT: - if (jump_target) - *jump_target = t; - else - { - /* Can happen with ({ return true; }) && false; passed to - maybe_constant_value. There is nothing to jump over in this - case, and the bug will be diagnosed later. */ - gcc_assert (ctx->quiet); - *non_constant_p = true; - } + *jump_target = t; break; case SAVE_EXPR: @@ -8063,9 +9206,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = v; else { - r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, - non_constant_p, overflow_p); - if (*non_constant_p) + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), + vc_prvalue, non_constant_p, + overflow_p, jump_target); + if (*non_constant_p || *jump_target) break; ctx->global->put_value (t, r); if (ctx->save_exprs) @@ -8073,16 +9217,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, } break; - case TRY_CATCH_EXPR: - if (TREE_OPERAND (t, 0) == NULL_TREE) - { - r = void_node; - break; - } - /* FALLTHRU */ case NON_LVALUE_EXPR: - case TRY_BLOCK: - case MUST_NOT_THROW_EXPR: case EXPR_STMT: case EH_SPEC_BLOCK: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), @@ -8091,6 +9226,42 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, jump_target); break; + case TRY_BLOCK: + r = cxx_eval_constant_expression (ctx, TRY_STMTS (t), lval, + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p && throws (jump_target)) + if (tree h = TRY_HANDLERS (t)) + { + tree type = strip_array_types (TREE_TYPE (*jump_target)); + if (TREE_CODE (h) == STATEMENT_LIST) + { + for (tree stmt : tsi_range (h)) + if (TREE_CODE (stmt) == HANDLER + && handler_match_for_exception_type (stmt, type)) + { + h = stmt; + break; + } + if (TREE_CODE (h) == STATEMENT_LIST) + h = NULL_TREE; + } + else if (TREE_CODE (h) != HANDLER + || !handler_match_for_exception_type (h, type)) + h = NULL_TREE; + if (h) + { + gcc_assert (VAR_P (*jump_target)); + ctx->global->caught_exceptions.safe_push (*jump_target); + ctx->global->caught_exceptions.safe_push (HANDLER_TYPE (h)); + *jump_target = NULL_TREE; + r = cxx_eval_constant_expression (ctx, HANDLER_BODY (h), + vc_discard, non_constant_p, + overflow_p, jump_target); + } + } + break; + case CLEANUP_POINT_EXPR: { auto_vec<tree, 2> cleanups; @@ -8108,47 +9279,132 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ctx->global->cleanups = prev_cleanups; unsigned int i; - tree cleanup; + tree cleanup, jmp_target = NULL_TREE; + bool eh = throws (jump_target); /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard, - non_constant_p, overflow_p); + if (cleanup == NULL_TREE) + { + /* NULL_TREE cleanup is a marker that before it is + CLEANUP_EH_ONLY cleanup. Skip the cleanup before it + if the body didn't throw. */ + if (!eh) + --i; + } + else + cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard, + non_constant_p, overflow_p, + &jmp_target); /* Forget SAVE_EXPRs and TARGET_EXPRs created by this full-expression. */ for (tree save_expr : save_exprs) destroy_value_checked (ctx, save_expr, non_constant_p); + if (throws (&jmp_target)) + *jump_target = jmp_target; } break; + case MUST_NOT_THROW_EXPR: + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), + lval, + non_constant_p, overflow_p, + jump_target); + if (throws (jump_target)) + { + /* [except.handle]/7 - If the search for a handler exits the + function body of a function with a non-throwing exception + specification, the function std::terminate is invoked. */ + if (!ctx->quiet) + { + auto_diagnostic_group d; + diagnose_std_terminate (loc, ctx, *jump_target); + if (MUST_NOT_THROW_NOEXCEPT_P (t) + && ctx->call + && ctx->call->fundef) + inform (loc, "uncaught exception exited from %<noexcept%> " + "function %qD", + ctx->call->fundef->decl); + else if (MUST_NOT_THROW_THROW_P (t)) + inform (loc, "destructor exited with an exception after " + "initializing the exception object"); + else if (MUST_NOT_THROW_CATCH_P (t)) + inform (loc, "constructor exited with another exception while " + "entering handler"); + } + *non_constant_p = true; + *jump_target = NULL_TREE; + r = NULL_TREE; + } + break; + + case TRY_CATCH_EXPR: + if (TREE_OPERAND (t, 0) == NULL_TREE) + { + r = void_node; + break; + } + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p, + jump_target); + if (!*non_constant_p && throws (jump_target)) + { + tree jmp_target = NULL_TREE; + cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); + } + break; + case TRY_FINALLY_EXPR: r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, non_constant_p, overflow_p, jump_target); if (!*non_constant_p) - /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, - non_constant_p, overflow_p); + { + tree jmp_target = NULL_TREE; + /* Also evaluate the cleanup. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == EH_ELSE_EXPR + && throws (jump_target)) + cxx_eval_constant_expression (ctx, + TREE_OPERAND (TREE_OPERAND (t, 1), + 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + else + cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); + } break; case EH_ELSE_EXPR: /* Evaluate any cleanup that applies to non-EH exits. */ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_discard, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); - /* We do not have constexpr exceptions yet, so skip the EH path. */ + /* The EH path is handled in TRY_FINALLY_EXPR handling above. */ break; case CLEANUP_STMT: r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, non_constant_p, overflow_p, jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) + if ((!CLEANUP_EH_ONLY (t) || throws (jump_target)) && !*non_constant_p) { iloc_sentinel ils (loc); + tree jmp_target = NULL_TREE; /* Also evaluate the cleanup. */ cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), vc_discard, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + &jmp_target); + r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target, + jmp_target); } break; @@ -8158,14 +9414,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case MEM_REF: case INDIRECT_REF: r = cxx_eval_indirect_ref (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case ADDR_EXPR: { tree oldop = TREE_OPERAND (t, 0); tree op = cxx_eval_constant_expression (ctx, oldop, vc_glvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) return t; @@ -8185,7 +9445,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (lval) { r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (r == error_mark_node) ; else if (r == TREE_OPERAND (t, 0) || lval == vc_discard) @@ -8206,7 +9469,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case FIXED_CONVERT_EXPR: case VEC_DUPLICATE_EXPR: r = cxx_eval_unary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case SIZEOF_EXPR: @@ -8244,6 +9508,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, cxx_eval_constant_expression (ctx, op0, vc_discard, non_constant_p, overflow_p, jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; op1 = TREE_OPERAND (t, 1); @@ -8296,7 +9562,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case RANGE_EXPR: case COMPLEX_EXPR: r = cxx_eval_binary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; /* fold can introduce non-IF versions of these; still treat them as @@ -8305,19 +9572,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case TRUTH_ANDIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_false_node, boolean_true_node, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: r = cxx_eval_logical_expression (ctx, t, boolean_true_node, boolean_false_node, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case ARRAY_REF: r = cxx_eval_array_reference (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case COMPONENT_REF: @@ -8332,17 +9602,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } r = cxx_eval_component_reference (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case BIT_FIELD_REF: r = cxx_eval_bit_field_ref (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case COND_EXPR: case IF_STMT: - if (jump_target && *jump_target) + if (*jump_target) { tree orig_jump = *jump_target; tree arg = ((TREE_CODE (t) != IF_STMT || TREE_OPERAND (t, 1)) @@ -8380,7 +9652,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case VEC_COND_EXPR: r = cxx_eval_vector_conditional_expression (ctx, t, non_constant_p, - overflow_p); + overflow_p, jump_target); break; case CONSTRUCTOR: @@ -8392,7 +9664,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return t; } r = cxx_eval_bare_aggregate (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case VEC_INIT_EXPR: @@ -8402,12 +9674,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, or xvalue of the same type, meaning direct-initialization from the corresponding member. */ r = cxx_eval_vec_init (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, jump_target); break; case VEC_PERM_EXPR: r = cxx_eval_trinary_expression (ctx, t, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case PAREN_EXPR: @@ -8415,7 +9688,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in constant expressions since it's unaffected by -fassociative-math. */ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); break; case NOP_EXPR: @@ -8439,7 +9713,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ? vc_discard : tcode == VIEW_CONVERT_EXPR ? lval : vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; tree type = TREE_TYPE (t); @@ -8450,7 +9727,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, @@ -8496,7 +9773,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, { if (integer_zerop (sop)) return build_int_cst (type, 0); - r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop); + r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop, + NULL, jump_target); + if (*jump_target) + return NULL_TREE; if (r) { r = build1 (ADDR_EXPR, type, r); @@ -8602,7 +9882,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); @@ -8623,10 +9903,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (cxx_replaceable_global_alloc_fn (fun) && IDENTIFIER_NEW_OP_P (DECL_NAME (fun))) arg_size = CALL_EXPR_ARG (oldop, 0); - TREE_TYPE (var) + tree new_type = build_new_constexpr_heap_type (ctx, elt_type, cookie_size, var_size, arg_size, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; + TREE_TYPE (var) = new_type; TREE_TYPE (TREE_OPERAND (op, 0)) = build_pointer_type (TREE_TYPE (var)); } @@ -8665,7 +9949,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, tree op = cxx_eval_constant_expression (ctx, oldop, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; if (*non_constant_p) return t; r = fold_convert (TREE_TYPE (t), op); @@ -8702,14 +9989,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: return cxx_eval_increment_expression (ctx, t, - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); + case THROW_EXPR: + if (cxx_dialect >= cxx26) + return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p, + jump_target); + /* FALLTHROUGH */ case LAMBDA_EXPR: case NEW_EXPR: case VEC_NEW_EXPR: case DELETE_EXPR: case VEC_DELETE_EXPR: - case THROW_EXPR: case MODOP_EXPR: /* GCC internal stuff. */ case VA_ARG_EXPR: @@ -8723,7 +10016,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case OBJ_TYPE_REF: /* Virtual function lookup. We don't need to do anything fancy. */ return cxx_eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t), - lval, non_constant_p, overflow_p); + lval, non_constant_p, overflow_p, + jump_target); case PLACEHOLDER_EXPR: /* Use of the value or address of the current object. */ @@ -8733,7 +10027,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return ctor; else return cxx_eval_constant_expression (ctx, ctor, lval, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); } /* A placeholder without a referent. We can get here when checking whether NSDMIs are noexcept, or in massage_init_elt; @@ -8746,7 +10041,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, { tree cond = TREE_OPERAND (t, 0); cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, - non_constant_p, overflow_p); + non_constant_p, overflow_p, + jump_target); + if (*jump_target) + return NULL_TREE; VERIFY_CONSTANT (cond); if (integer_nonzerop (cond)) *jump_target = t; @@ -8858,7 +10156,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; } - r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p); + r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p, jump_target); break; case OMP_PARALLEL: @@ -8997,20 +10295,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 @@ -9094,11 +10378,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, { if (cxx_dialect < cxx20) return t; - if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR) + /* We could have a COMPOUND_EXPR here coming from + keep_unused_object_arg. */ + tree x = extract_call_expr (t); + if (x == NULL_TREE || x == error_mark_node) return t; /* Calls to immediate functions returning void need to be evaluated. */ - tree fndecl = cp_get_callee_fndecl_nofold (t); + tree fndecl = cp_get_callee_fndecl_nofold (x); if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl)) return t; else @@ -9116,6 +10403,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)) { @@ -9182,30 +10478,67 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (manifestly_const_eval == mce_true) instantiate_constexpr_fns (r); + tree jmp_target = NULL_TREE; r = cxx_eval_constant_expression (&ctx, r, vc_prvalue, - &non_constant_p, &overflow_p); + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) && !non_constant_p) + { + if (!ctx.quiet) + diagnose_uncaught_exception (input_location, &ctx, jmp_target); + non_constant_p = true; + jmp_target = NULL_TREE; + r = t; + } + else if (!non_constant_p && jmp_target) + { + non_constant_p = true; + if (!ctx.quiet) + { + if (breaks (&jmp_target)) + error ("%<break%> outside of a loop or %<switch%>"); + else if (continues (&jmp_target)) + error ("%<continue%> outside of a loop"); + else if (returns (&jmp_target)) + error ("%<return%> in a statement expression"); + else + gcc_unreachable (); + } + r = t; + } /* If we got a non-simple TARGET_EXPR, the initializer was a sequence of statements, and the result ought to be stored in ctx.ctor. */ if (r == void_node && !constexpr_dtor && ctx.ctor) r = ctx.ctor; - if (!constexpr_dtor) - verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - else - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; - unsigned int i; tree cleanup; + jmp_target = NULL_TREE; /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (&ctx, cleanup, vc_discard, - &non_constant_p, &overflow_p); + if (cleanup == NULL_TREE) + /* NULL_TREE cleanup is a marker that before it is + CLEANUP_EH_ONLY cleanup. Skip the cleanup before it. */ + --i; + else + cxx_eval_constant_expression (&ctx, cleanup, vc_discard, + &non_constant_p, &overflow_p, + &jmp_target); + if (throws (&jmp_target) && !non_constant_p) + { + if (!ctx.quiet) + diagnose_uncaught_exception (input_location, &ctx, jmp_target); + non_constant_p = true; + r = t; + } /* Mutable logic is a bit tricky: we want to allow initialization of constexpr variables with mutable members, but we can't copy those members to another constexpr variable. */ - if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r)) + if (!non_constant_p + && TREE_CODE (r) == CONSTRUCTOR + && CONSTRUCTOR_MUTABLE_POISON (r)) { if (!allow_non_constant) error ("%qE is not a constant expression because it refers to " @@ -9213,15 +10546,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 +10555,16 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (heap_var) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because it refers to " - "a result of %<operator new%>", t); + { + if (DECL_LANG_SPECIFIC (heap_var)) + error ("%qE is not a constant expression because it refers to " + "exception object allocated with " + "%<__cxa_allocate_exception%>", t); + else + error ("%qE is not a constant expression because it refers to " + "a result of %<operator new%>", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9242,13 +10573,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 +10606,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 +10636,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))) { @@ -9448,6 +10798,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; @@ -9467,8 +10820,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) @@ -9486,6 +10866,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); @@ -9515,7 +10899,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; } @@ -9679,7 +11063,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; @@ -9705,17 +11089,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) @@ -9732,6 +11126,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); } @@ -9740,7 +11140,25 @@ maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) tree cxx_constant_init (tree t, tree decl) { - return maybe_constant_init_1 (t, decl, false, true); + return maybe_constant_init_1 (t, decl, false, mce_true); +} + +/* Return true if CALL_EXPR T might throw during constant evaluation. */ + +static bool +callee_might_throw (tree t) +{ + if (cxx_dialect < cxx26 || !flag_exceptions) + return false; + tree callee = cp_get_callee (t); + if (callee == NULL_TREE) + return false; + tree callee_fn = cp_get_fndecl_from_callee (callee, false); + return (!flag_enforce_eh_specs + || type_dependent_expression_p (callee) + || !POINTER_TYPE_P (TREE_TYPE (callee)) + || (!type_noexcept_p (TREE_TYPE (TREE_TYPE (callee))) + && (callee_fn == NULL_TREE || !TREE_NOTHROW (callee_fn)))); } #if 0 @@ -9775,11 +11193,13 @@ struct check_for_return_continue_data { hash_set<tree> *pset; tree continue_stmt; tree break_stmt; + bool could_throw; }; /* Helper function for potential_constant_expression_1 SWITCH_STMT handling, called through cp_walk_tree. Return the first RETURN_EXPR found, or note - the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. */ + the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. + For C++26 also note presence of possibly throwing calls. */ static tree check_for_return_continue (tree *tp, int *walk_subtrees, void *data) { @@ -9864,6 +11284,13 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data) case CONSTRUCTOR: break; + case AGGR_INIT_EXPR: + case CALL_EXPR: + /* In C++26 a function could throw. */ + if (callee_might_throw (t)) + d->could_throw = true; + break; + default: if (!EXPR_P (t)) *walk_subtrees = 0; @@ -9923,6 +11350,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t)) && !NULLPTR_TYPE_P (TREE_TYPE (t))) { + if (TREE_CLOBBER_P (t)) + { + /* We should have caught any clobbers in INIT/MODIFY_EXPR. */ + gcc_checking_assert (false); + return true; + } + if (flags & tf_error) constexpr_error (loc, fundef_p, "lvalue-to-rvalue conversion of " "a volatile lvalue %qE with type %qT", t, @@ -10069,8 +11503,27 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, || TREE_CODE (t) != CALL_EXPR || current_function_decl == NULL_TREE || !is_std_construct_at (current_function_decl)) - && !cxx_dynamic_cast_fn_p (fun)) + && !cxx_dynamic_cast_fn_p (fun) + && !cxx_cxa_builtin_fn_p (fun)) { + /* In C++26 evaluation of the function arguments might + throw and in that case it is irrelevant whether + fun is constexpr or not. */ + if (cxx_dialect >= cxx26) + for (; i < nargs; ++i) + { + tree x = get_nth_callarg (t, i); + bool rv = processing_template_decl ? any : rval; + bool sub_now = false; + if (!potential_constant_expression_1 (x, rv, strict, + sub_now, + fundef_p, + flags, + jump_target)) + return false; + if (throws (jump_target)) + return true; + } if ((flags & tf_error) && constexpr_error (loc, fundef_p, "call to non-%<constexpr%> " @@ -10115,7 +11568,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, sub_now, fundef_p, flags, jump_target)) return false; + if (throws (jump_target)) + return true; } + /* In C++26 a function could throw. */ + if (*jump_target == NULL_TREE && callee_might_throw (t)) + *jump_target = void_node; return true; } @@ -10160,12 +11618,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } return false; } + tree ve = DECL_VALUE_EXPR (t); /* Treat __PRETTY_FUNCTION__ inside a template function as potentially-constant. */ - else if (DECL_PRETTY_FUNCTION_P (t) - && DECL_VALUE_EXPR (t) == error_mark_node) + if (DECL_PRETTY_FUNCTION_P (t) && ve == error_mark_node) return true; - return RECUR (DECL_VALUE_EXPR (t), rval); + if (DECL_DECOMPOSITION_P (t) && TREE_CODE (ve) == TREE_VEC) + return RECUR (TREE_VEC_ELT (ve, 0), rval); + return RECUR (ve, rval); } if (want_rval && (now || !var_in_maybe_constexpr_fn (t)) @@ -10338,11 +11798,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, a return. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&FOR_BODY (t), check_for_return_continue, &data, &pset)) *jump_target = ret_expr; + if (data.could_throw) + *jump_target = void_node; return true; } } @@ -10382,11 +11844,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, a return. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&WHILE_BODY (t), check_for_return_continue, &data, &pset)) *jump_target = ret_expr; + if (data.could_throw) + *jump_target = void_node; return true; } if (!RECUR (WHILE_BODY (t), any)) @@ -10410,7 +11874,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, { hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, false }; if (tree ret_expr = cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue, &data, &pset)) @@ -10419,6 +11883,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, else if (data.continue_stmt) /* The switch can't return, but might continue. */ *jump_target = data.continue_stmt; + if (data.could_throw) + *jump_target = void_node; } return true; @@ -10448,7 +11914,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case DYNAMIC_CAST_EXPR: case PSEUDO_DTOR_EXPR: - case THROW_EXPR: case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: @@ -10499,6 +11964,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, "expression", t); return false; + case OMP_DECLARE_MAPPER: + /* This can be used to initialize VAR_DECLs: it's treated as a magic + constant. */ + return true; + + case THROW_EXPR: + if (cxx_dialect < cxx26) + goto fail; + return RECUR (TREE_OPERAND (t, 0), rval); + case ASM_EXPR: if (flags & tf_error) inline_asm_in_constexpr_error (loc, fundef_p); @@ -10627,6 +12102,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CLEANUP_POINT_EXPR: case MUST_NOT_THROW_EXPR: case TRY_CATCH_EXPR: + /* Even for C++26 handle TRY_BLOCK conservatively, if we detect the + body could throw, even with catch (...) among handlers we'd need + to analyze them in detail if they couldn't rethrow it. More + importantly though, throws (jump_target) is just conservative, + and there could be e.g. + try + { + possibly_throwing_fn (args); + break; + } + catch (...) + { + } + or continue or return instead of break. So, clearing *jump_target + because we see catch (...) handler might mean we missed break + etc. */ case TRY_BLOCK: case EH_SPEC_BLOCK: case EXPR_STMT: @@ -10691,6 +12182,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } /* FALLTHRU */ case INIT_EXPR: + if (TREE_CLOBBER_P (TREE_OPERAND (t, 1))) + return true; return RECUR (TREE_OPERAND (t, 1), rval); case CONSTRUCTOR: @@ -10868,9 +12361,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, want_rval, strict, now, fundef_p, tf_none, &this_jump_target)) { - if (returns (&this_jump_target)) + if (returns (&this_jump_target) || throws (&this_jump_target)) *jump_target = this_jump_target; - else if (!returns (jump_target)) + else if (!returns (jump_target) && !throws (jump_target)) { if (breaks (&this_jump_target) || continues (&this_jump_target)) @@ -10882,7 +12375,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, couldn't return, break or continue. */ hash_set<tree> pset; check_for_return_continue_data data = { &pset, NULL_TREE, - NULL_TREE }; + NULL_TREE, + false }; if (tree ret_expr = cp_walk_tree (&TREE_OPERAND (t, 2), check_for_return_continue, &data, @@ -10895,6 +12389,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, else if (data.break_stmt) *jump_target = data.break_stmt; } + if (data.could_throw) + *jump_target = void_node; } } return true; @@ -10946,6 +12442,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"); @@ -10979,6 +12478,10 @@ 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: + case TEMPLATE_FOR_STMT: + 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 2f1678c..4b20b79 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -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,19 +1845,67 @@ 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)) + { + 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) { - 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 (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 @@ -2442,10 +2490,11 @@ satisfy_atom (tree t, tree args, sat_info info) result = force_rvalue (result, info.complain); if (result == error_mark_node) return cache.save (inst_cache.save (error_mark_node)); + tree substituted = result; if (!same_type_p (TREE_TYPE (result), boolean_type_node)) { if (info.noisy ()) - diagnose_atomic_constraint (t, args, result, info); + diagnose_atomic_constraint (t, args, substituted, info); return cache.save (inst_cache.save (error_mark_node)); } @@ -2463,7 +2512,7 @@ satisfy_atom (tree t, tree args, sat_info info) } result = satisfaction_value (result); if (result == boolean_false_node && info.diagnose_unsatisfaction_p ()) - diagnose_atomic_constraint (t, args, result, info); + diagnose_atomic_constraint (t, args, substituted, info); return cache.save (inst_cache.save (result)); } @@ -2704,6 +2753,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 +2783,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 (); @@ -3013,11 +3064,9 @@ get_constraint_error_location (tree t) /* Emit a diagnostic for a failed trait. */ -static void -diagnose_trait_expr (tree expr, tree args) +void +diagnose_trait_expr (location_t loc, tree expr, tree args) { - location_t loc = cp_expr_location (expr); - /* Build a "fake" version of the instantiated trait, so we can get the instantiated types from result. */ ++processing_template_decl; @@ -3026,197 +3075,248 @@ diagnose_trait_expr (tree expr, tree args) tree t1 = TRAIT_EXPR_TYPE1 (expr); tree t2 = TRAIT_EXPR_TYPE2 (expr); - if (t2 && TREE_CODE (t2) == TREE_VEC) - { - /* Convert the TREE_VEC of arguments into a TREE_LIST, since we can't - directly print a TREE_VEC but we can a TREE_LIST via the E format - specifier. */ - tree list = NULL_TREE; - for (tree t : tree_vec_range (t2)) - list = tree_cons (NULL_TREE, t, list); - t2 = nreverse (list); - } + + /* For traits intrinsically about the properties of user-defined types, + decl_loc will point to the declaration of that type. */ + location_t decl_loc = location_of (t1); + if (decl_loc == input_location) + decl_loc = loc; + switch (TRAIT_EXPR_KIND (expr)) { case CPTK_HAS_NOTHROW_ASSIGN: - inform (loc, " %qT is not nothrow copy assignable", t1); + inform (decl_loc, "%qT is not nothrow copy assignable", t1); break; case CPTK_HAS_NOTHROW_CONSTRUCTOR: - inform (loc, " %qT is not nothrow default constructible", t1); + inform (decl_loc, "%qT is not nothrow default constructible", t1); break; case CPTK_HAS_NOTHROW_COPY: - inform (loc, " %qT is not nothrow copy constructible", t1); + inform (decl_loc, "%qT is not nothrow copy constructible", t1); break; case CPTK_HAS_TRIVIAL_ASSIGN: - inform (loc, " %qT is not trivially copy assignable", t1); + inform (decl_loc, "%qT is not trivially copy assignable", t1); break; case CPTK_HAS_TRIVIAL_CONSTRUCTOR: - inform (loc, " %qT is not trivially default constructible", t1); + inform (decl_loc, "%qT is not trivially default constructible", t1); break; case CPTK_HAS_TRIVIAL_COPY: - inform (loc, " %qT is not trivially copy constructible", t1); + inform (decl_loc, "%qT is not trivially copy constructible", t1); break; case CPTK_HAS_TRIVIAL_DESTRUCTOR: - inform (loc, " %qT is not trivially destructible", t1); + inform (decl_loc, "%qT is not trivially destructible", t1); break; case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: - inform (loc, " %qT does not have unique object representations", t1); + inform (decl_loc, "%qT does not have unique object representations", t1); break; case CPTK_HAS_VIRTUAL_DESTRUCTOR: - inform (loc, " %qT does not have a virtual destructor", t1); + { + location_t dtor_loc = decl_loc; + if (NON_UNION_CLASS_TYPE_P (t1)) + if (tree dtor = CLASSTYPE_DESTRUCTOR (t1)) + dtor_loc = DECL_SOURCE_LOCATION (dtor); + inform (dtor_loc, "%qT does not have a virtual destructor", t1); + } break; case CPTK_IS_ABSTRACT: - inform (loc, " %qT is not an abstract class", t1); + inform (decl_loc, "%qT is not an abstract class", t1); break; case CPTK_IS_AGGREGATE: - inform (loc, " %qT is not an aggregate", t1); + inform (decl_loc, "%qT is not an aggregate", t1); break; case CPTK_IS_ARRAY: - inform (loc, " %qT is not an array", t1); + inform (loc, "%qT is not an array", t1); break; case CPTK_IS_ASSIGNABLE: - inform (loc, " %qT is not assignable from %qT", t1, t2); + inform (loc, "%qT is not assignable from %qT, because", t1, t2); + is_xible (MODIFY_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_BASE_OF: - inform (loc, " %qT is not a base of %qT", t1, t2); + inform (decl_loc, "%qT is not a base of %qT", t1, t2); break; case CPTK_IS_BOUNDED_ARRAY: - inform (loc, " %qT is not a bounded array", t1); + inform (loc, "%qT is not a bounded array", t1); break; case CPTK_IS_CLASS: - inform (loc, " %qT is not a class", t1); + inform (decl_loc, "%qT is not a class", t1); break; case CPTK_IS_CONST: - inform (loc, " %qT is not a const type", t1); + inform (loc, "%qT is not a const type", t1); break; case CPTK_IS_CONSTRUCTIBLE: - if (!t2) - inform (loc, " %qT is not default constructible", t1); + if (!TREE_VEC_LENGTH (t2)) + inform (loc, "%qT is not default constructible, because", t1); else - inform (loc, " %qT is not constructible from %qE", t1, t2); + inform (loc, "%qT is not constructible from %qT, because", t1, t2); + is_xible (INIT_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_CONVERTIBLE: - inform (loc, " %qT is not convertible from %qE", t2, t1); + /* The errors produced here all seem to mention "convertible" in the + diagnostic, so an extra inform here appears redundant. */ + is_convertible (t1, t2, /*explain=*/true); + break; + case CPTK_IS_DESTRUCTIBLE: + inform (loc, "%qT is not destructible, because", t1); + is_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true); break; case CPTK_IS_EMPTY: - inform (loc, " %qT is not an empty class", t1); + inform (decl_loc, "%qT is not an empty class", t1); break; case CPTK_IS_ENUM: - inform (loc, " %qT is not an enum", t1); + inform (decl_loc, "%qT is not an enum", t1); break; case CPTK_IS_FINAL: - inform (loc, " %qT is not a final class", t1); + inform (decl_loc, "%qT is not a final class", t1); break; case CPTK_IS_FUNCTION: - inform (loc, " %qT is not a function", t1); + inform (loc, "%qT is not a function", t1); break; case CPTK_IS_INVOCABLE: - if (!t2) - inform (loc, " %qT is not invocable", t1); - else - inform (loc, " %qT is not invocable by %qE", t1, t2); + { + if (!TREE_VEC_LENGTH (t2)) + inform (loc, "%qT is not invocable, because", t1); + else + inform (loc, "%qT is not invocable by %qT, because", t1, t2); + build_invoke (t1, t2, tf_error); + } break; case CPTK_IS_LAYOUT_COMPATIBLE: - inform (loc, " %qT is not layout compatible with %qT", t1, t2); + inform (loc, "%qT is not layout compatible with %qT", t1, t2); break; case CPTK_IS_LITERAL_TYPE: - inform (loc, " %qT is not a literal type", t1); + inform (decl_loc, "%qT is not a literal type", t1); break; case CPTK_IS_MEMBER_FUNCTION_POINTER: - inform (loc, " %qT is not a member function pointer", t1); + inform (loc, "%qT is not a member function pointer", t1); break; case CPTK_IS_MEMBER_OBJECT_POINTER: - inform (loc, " %qT is not a member object pointer", t1); + inform (loc, "%qT is not a member object pointer", t1); break; case CPTK_IS_MEMBER_POINTER: - inform (loc, " %qT is not a member pointer", t1); + inform (loc, "%qT is not a member pointer", t1); break; case CPTK_IS_NOTHROW_ASSIGNABLE: - inform (loc, " %qT is not nothrow assignable from %qT", t1, t2); + inform (loc, "%qT is not nothrow assignable from %qT, because", t1, t2); + is_nothrow_xible (MODIFY_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_NOTHROW_CONSTRUCTIBLE: - if (!t2) - inform (loc, " %qT is not nothrow default constructible", t1); + if (!TREE_VEC_LENGTH (t2)) + inform (loc, "%qT is not nothrow default constructible, because", t1); else - inform (loc, " %qT is not nothrow constructible from %qE", t1, t2); + inform (loc, "%qT is not nothrow constructible from %qT, because", + t1, t2); + is_nothrow_xible (INIT_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_NOTHROW_CONVERTIBLE: - inform (loc, " %qT is not nothrow convertible from %qE", t2, t1); + inform (loc, "%qT is not nothrow convertible from %qT, because", t1, t2); + is_nothrow_convertible (t1, t2, /*explain=*/true); + break; + case CPTK_IS_NOTHROW_DESTRUCTIBLE: + inform (loc, "%qT is not nothrow destructible, because", t1); + is_nothrow_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true); break; case CPTK_IS_NOTHROW_INVOCABLE: - if (!t2) - inform (loc, " %qT is not nothrow invocable", t1); - else - inform (loc, " %qT is not nothrow invocable by %qE", t1, t2); + { + if (!TREE_VEC_LENGTH (t2)) + inform (loc, "%qT is not nothrow invocable, because", t1); + else + inform (loc, "%qT is not nothrow invocable by %qT, because", t1, t2); + tree call = build_invoke (t1, t2, tf_error); + if (call != error_mark_node) + explain_not_noexcept (call); + } + break; + case CPTK_IS_NOTHROW_RELOCATABLE: + inform (loc, "%qT is not nothrow relocatable", t1); break; case CPTK_IS_OBJECT: - inform (loc, " %qT is not an object type", t1); + inform (loc, "%qT is not an object type", t1); break; case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: - inform (loc, " %qT is not pointer-interconvertible base of %qT", + inform (decl_loc, "%qT is not a pointer-interconvertible base of %qT", t1, t2); break; case CPTK_IS_POD: - inform (loc, " %qT is not a POD type", t1); + inform (loc, "%qT is not a POD type", t1); break; case CPTK_IS_POINTER: - inform (loc, " %qT is not a pointer", t1); + inform (loc, "%qT is not a pointer", t1); break; case CPTK_IS_POLYMORPHIC: - inform (loc, " %qT is not a polymorphic type", t1); + inform (decl_loc, "%qT is not a polymorphic type", t1); break; case CPTK_IS_REFERENCE: - inform (loc, " %qT is not a reference", t1); + inform (loc, "%qT is not a reference", t1); + break; + case CPTK_IS_REPLACEABLE: + inform (loc, "%qT is not replaceable", t1); break; case CPTK_IS_SAME: - inform (loc, " %qT is not the same as %qT", t1, t2); + inform (loc, "%q#T is not the same as %q#T", t1, t2); break; case CPTK_IS_SCOPED_ENUM: - inform (loc, " %qT is not a scoped enum", t1); + inform (decl_loc, "%qT is not a scoped enum", t1); break; case CPTK_IS_STD_LAYOUT: - inform (loc, " %qT is not an standard layout type", t1); + inform (decl_loc, "%qT is not a standard layout type", t1); break; case CPTK_IS_TRIVIAL: - inform (loc, " %qT is not a trivial type", t1); + inform (decl_loc, "%qT is not a trivial type", t1); break; case CPTK_IS_TRIVIALLY_ASSIGNABLE: - inform (loc, " %qT is not trivially assignable from %qT", t1, t2); + inform (loc, "%qT is not trivially assignable from %qT, because", t1, t2); + is_trivially_xible (MODIFY_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: - if (!t2) - inform (loc, " %qT is not trivially default constructible", t1); + if (!TREE_VEC_LENGTH (t2)) + inform (loc, "%qT is not trivially default constructible, because", t1); else - inform (loc, " %qT is not trivially constructible from %qE", t1, t2); + inform (loc, "%qT is not trivially constructible from %qT, because", + t1, t2); + is_trivially_xible (INIT_EXPR, t1, t2, /*explain=*/true); break; case CPTK_IS_TRIVIALLY_COPYABLE: - inform (loc, " %qT is not trivially copyable", t1); + inform (decl_loc, "%qT is not trivially copyable", t1); + break; + case CPTK_IS_TRIVIALLY_DESTRUCTIBLE: + inform (loc, "%qT is not trivially destructible, because", t1); + is_trivially_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true); + break; + case CPTK_IS_TRIVIALLY_RELOCATABLE: + inform (loc, "%qT is not trivially relocatable", t1); break; case CPTK_IS_UNBOUNDED_ARRAY: - inform (loc, " %qT is not an unbounded array", t1); + inform (loc, "%qT is not an unbounded array", t1); break; case CPTK_IS_UNION: - inform (loc, " %qT is not a union", t1); + inform (decl_loc, "%qT is not a union", t1); break; case CPTK_IS_VIRTUAL_BASE_OF: - inform (loc, " %qT is not a virtual base of %qT", t1, t2); + inform (decl_loc, "%qT is not a virtual base of %qT", t1, t2); + if (CLASS_TYPE_P (t2)) + inform (location_of (t2), "%qT declared here", t2); break; case CPTK_IS_VOLATILE: - inform (loc, " %qT is not a volatile type", t1); + inform (loc, "%qT is not a volatile type", t1); break; case CPTK_RANK: - inform (loc, " %qT cannot yield a rank", t1); + inform (loc, "%qT cannot yield a rank", t1); + break; + case CPTK_TYPE_ORDER: + inform (loc, "%qT and %qT cannot be ordered", t1, t2); + break; + case CPTK_STRUCTURED_BINDING_SIZE: + inform (loc, "%qT is not destructurable", t1); break; case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: - inform (loc, " %qT is not a reference that binds to a temporary " + inform (loc, "%qT is not a reference that binds to a temporary " "object of type %qT (direct-initialization)", t1, t2); break; case CPTK_REF_CONVERTS_FROM_TEMPORARY: - inform (loc, " %qT is not a reference that binds to a temporary " + inform (loc, "%qT is not a reference that binds to a temporary " "object of type %qT (copy-initialization)", t1, t2); break; case CPTK_IS_DEDUCIBLE: - inform (loc, " %qD is not deducible from %qT", t1, t2); + inform (loc, "%qD is not deducible from %qT", t1, t2); break; #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ case CPTK_##CODE: @@ -3229,10 +3329,50 @@ diagnose_trait_expr (tree expr, tree args) } } +/* Attempt to detect if this is a standard type trait, defined in terms + of a compiler builtin (above). If so, this will allow us to provide + more helpful diagnostics. */ + +bool +maybe_diagnose_standard_trait (location_t loc, tree expr) +{ + gcc_assert (TREE_CODE (expr) != TRAIT_EXPR); + expr = tree_strip_nop_conversions (expr); + + /* TODO: in some cases it would be possible to provide more helpful + diagnostics for negations of traits, e.g. '!is_same_v<T1, T2>'. */ + + tree args = NULL_TREE; + if (VAR_P (expr) && DECL_LANG_SPECIFIC (expr) && DECL_USE_TEMPLATE (expr)) + { + tree tinfo = DECL_TEMPLATE_INFO (expr); + if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) && TI_PARTIAL_INFO (tinfo)) + tinfo = TI_PARTIAL_INFO (tinfo); + else if (DECL_TEMPLATE_SPECIALIZATION (expr)) + /* In an explicit specialisation we no longer know what the original + initializer looked like. */ + tinfo = NULL_TREE; + + if (tinfo) + { + expr = DECL_INITIAL (DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo))); + args = TI_ARGS (tinfo); + } + } + + if (TREE_CODE (expr) == TRAIT_EXPR) + { + diagnose_trait_expr (loc, expr, args); + return true; + } + + return false; +} + /* Diagnose a substitution failure in the atomic constraint T using ARGS. */ static void -diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) +diagnose_atomic_constraint (tree t, tree args, tree substituted, sat_info info) { /* If the constraint is already ill-formed, we've previously diagnosed the reason. We should still say why the constraints aren't satisfied. */ @@ -3253,25 +3393,26 @@ diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info) /* Generate better diagnostics for certain kinds of expressions. */ tree expr = ATOMIC_CONSTR_EXPR (t); STRIP_ANY_LOCATION_WRAPPER (expr); - switch (TREE_CODE (expr)) + + if (TREE_CODE (expr) == REQUIRES_EXPR) { - case TRAIT_EXPR: - diagnose_trait_expr (expr, args); - break; - case REQUIRES_EXPR: gcc_checking_assert (info.diagnose_unsatisfaction_p ()); /* Clear in_decl before replaying the substitution to avoid emitting seemingly unhelpful "in declaration ..." notes that follow some substitution failure error messages. */ info.in_decl = NULL_TREE; tsubst_requires_expr (expr, args, info); - break; - default: - if (!same_type_p (TREE_TYPE (result), boolean_type_node)) - error_at (loc, "constraint %qE has type %qT, not %<bool%>", - t, TREE_TYPE (result)); + } + else if (!same_type_p (TREE_TYPE (substituted), boolean_type_node)) + error_at (loc, "constraint %qE has type %qT, not %<bool%>", + t, TREE_TYPE (substituted)); + else + { + inform (loc, "the expression %qE evaluated to %<false%>", t); + if (TREE_CODE (expr) == TRAIT_EXPR) + diagnose_trait_expr (loc, expr, args); else - inform (loc, "the expression %qE evaluated to %<false%>", t); + maybe_diagnose_standard_trait (loc, substituted); } } diff --git a/gcc/cp/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..690e510 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); + finish_expr_stmt (c); - /* 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 (); - 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 @@ -4944,6 +5050,8 @@ cp_coroutine_transform::build_ramp_function () check the returned pointer and call the func if it's null. Otherwise, no check, and we fail for noexcept/fno-exceptions cases. */ + tree grooaf_if_stmt = NULL_TREE; + tree alloc_ok_scope = NULL_TREE; if (grooaf) { /* [dcl.fct.def.coroutine] / 10 (part 3) @@ -4951,53 +5059,42 @@ cp_coroutine_transform::build_ramp_function () control to the caller of the coroutine and the return value is obtained by a call to T::get_return_object_on_allocation_failure(), where T is the promise type. */ - tree if_stmt = begin_if_stmt (); tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node); - cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond); - finish_if_stmt_cond (cond, if_stmt); - r = NULL_TREE; - if (void_ramp_p) - /* Execute the get-return-object-on-alloc-fail call... */ - finish_expr_stmt (grooaf); - else - /* Get the fallback return object. */ - r = grooaf; - finish_return_stmt (r); - finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); + cond = build2 (NE_EXPR, boolean_type_node, coro_fp, cond); + grooaf_if_stmt = begin_if_stmt (); + finish_if_stmt_cond (cond, grooaf_if_stmt); + alloc_ok_scope = begin_compound_stmt (BCS_NORMAL); } + /* Dereference the frame pointer, to use in member access code. */ + 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 +5166,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 +5227,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 +5251,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 +5268,80 @@ 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); - } + /* 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. */ - finish_expr_stmt (r); - - 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); + 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); + /* This is our 'normal' exit. */ + r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro); + finish_return_stmt (r); - if (flag_exceptions) + if (grooaf) { - finish_compound_stmt (ramp_try_stmts); - finish_try_block (ramp_try_block); - tree handler = begin_handler (); - finish_handler_parms (NULL_TREE, handler); /* catch (...) */ + finish_compound_stmt (alloc_ok_scope); + finish_then_clause (grooaf_if_stmt); - /* 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); + begin_else_clause (grooaf_if_stmt); + /* We come here if the frame allocation failed. */ + r = NULL_TREE; + if (void_ramp_p) + /* Execute the get-return-object-on-alloc-fail call... */ + finish_expr_stmt (grooaf); + else + /* Get the fallback return object. */ + r = grooaf; + finish_return_stmt (r); + finish_if_stmt (grooaf_if_stmt); } + finish_compound_stmt (ramp_fnbody); return true; } @@ -5346,9 +5372,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 +5416,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 +5442,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 +5453,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..4ff8f36a 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -690,6 +690,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) op1 = build_fold_addr_expr (op1); + suppress_warning (op1, OPT_Wunused_result); gimplify_and_add (op1, pre_p); } gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, @@ -889,6 +890,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), &CALL_EXPR_ARG (*expr_p, 0)); break; + case CP_BUILT_IN_EH_PTR_ADJUST_REF: + error_at (EXPR_LOCATION (*expr_p), + "%qs used outside of constant expressions", + "__builtin_eh_ptr_adjust_ref"); + *expr_p = void_node; + break; default: break; } @@ -1199,8 +1206,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 +1480,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 +1501,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 +2821,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 @@ -3006,7 +3029,7 @@ cp_fold (tree x, fold_flags_t flags) case CLEANUP_POINT_EXPR: /* Strip CLEANUP_POINT_EXPR if the expression doesn't have side effects. */ - r = cp_fold_rvalue (TREE_OPERAND (x, 0), flags); + r = cp_fold (TREE_OPERAND (x, 0), flags); if (!TREE_SIDE_EFFECTS (r)) x = r; break; @@ -3195,7 +3218,16 @@ cp_fold (tree x, fold_flags_t flags) loc = EXPR_LOCATION (x); op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops, flags); - op1 = cp_fold_rvalue (TREE_OPERAND (x, 1), flags); + bool clear_decl_read; + clear_decl_read = false; + if (code == MODIFY_EXPR + && (VAR_P (op0) || TREE_CODE (op0) == PARM_DECL) + && !DECL_READ_P (op0)) + clear_decl_read = true; + op1 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 1), + code != COMPOUND_EXPR, flags); + if (clear_decl_read) + DECL_READ_P (op0) = 0; /* decltype(nullptr) has only one value, so optimize away all comparisons with that type right away, keeping them in the IL causes troubles for @@ -3338,19 +3370,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 +3468,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 +3903,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 +3935,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..ee1c0ba 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 @@ -657,6 +659,7 @@ cp_common_init_ts (void) MARK_TS_EXP (IF_STMT); MARK_TS_EXP (OMP_DEPOBJ); MARK_TS_EXP (RANGE_FOR_STMT); + MARK_TS_EXP (TEMPLATE_FOR_STMT); MARK_TS_EXP (TRY_BLOCK); MARK_TS_EXP (USING_STMT); 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..5e4493a 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,13 +85,16 @@ 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_NOTHROW_RELOCATABLE, "__builtin_is_nothrow_relocatable", 1) DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1) DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1) DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1) +DEFTRAIT_EXPR (IS_REPLACEABLE, "__builtin_is_replaceable", 1) DEFTRAIT_EXPR (IS_SAME, "__is_same", 2) DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1) DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1) @@ -98,6 +102,8 @@ 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_TRIVIALLY_RELOCATABLE, "__builtin_is_trivially_relocatable", 1) DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1) DEFTRAIT_EXPR (IS_UNION, "__is_union", 1) DEFTRAIT_EXPR (IS_VIRTUAL_BASE_OF, "__builtin_is_virtual_base_of", 2) @@ -111,6 +117,8 @@ 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 (STRUCTURED_BINDING_SIZE, "__builtin_structured_binding_size", 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.def b/gcc/cp/cp-tree.def index bb5aaf9..b1e3697 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -299,6 +299,11 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4) templates. */ DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6) +/* Used to represent an expansion-statement. The operands are + TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY, + TEMPLATE_FOR_SCOPE, and TEMPLATE_FOR_INIT_STMT, respectively. */ +DEFTREECODE (TEMPLATE_FOR_STMT, "template_for_stmt", tcc_statement, 5) + /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to obtain the expression. */ DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 927f51b..55e8e07 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -452,6 +452,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR) PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*) + MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR) + CONSTEVAL_BLOCK_P (in STATIC_ASSERT) + LAMBDA_EXPR_CONSTEVAL_BLOCK_P (in LAMBDA_EXPR) 1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -472,6 +475,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; BIND_EXPR_VEC_DTOR (in BIND_EXPR) ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR) STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates) + MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR) + LAMBDA_EXPR_CONST_QUAL_P (in LAMBDA_EXPR) 2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -493,6 +498,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST for {static,tls}_aggregates) + MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR) 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -506,6 +512,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) TARGET_EXPR_ELIDING_P (in TARGET_EXPR) contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) + TYPENAME_IS_UNION_P (in TYPENAME_TYPE) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -1429,6 +1436,10 @@ struct GTY (()) tree_deferred_noexcept { #define STATIC_ASSERT_SOURCE_LOCATION(NODE) \ (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location) +/* True if this static assert represents a C++26 consteval block. */ +#define CONSTEVAL_BLOCK_P(NODE) \ + TREE_LANG_FLAG_0 (STATIC_ASSERT_CHECK (NODE)) + struct GTY (()) tree_static_assert { struct tree_base base; tree condition; @@ -1543,6 +1554,17 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_THIS_CAPTURE(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture) +/* True iff this lambda was created for a consteval block. */ +#define LAMBDA_EXPR_CONSTEVAL_BLOCK_P(NODE) \ + TREE_LANG_FLAG_0 (LAMBDA_EXPR_CHECK (NODE)) + +/* True if we should add "const" when figuring out the type of an entity + in a lambda. This is false in the parameter-declaration-clause of + a lambda; after that, it will remain false if the mutable keyword is + present. */ +#define LAMBDA_EXPR_CONST_QUAL_P(NODE) \ + TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE)) + /* True iff uses of a const variable capture were optimized away. */ #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) @@ -1959,6 +1981,8 @@ struct GTY(()) saved_scope { of consteval if statement. Also set while processing an immediate invocation. */ BOOL_BITFIELD consteval_if_p : 1; + /* Nonzero if we are parsing the substatement of expansion-statement. */ + BOOL_BITFIELD expansion_stmt : 1; int unevaluated_operand; int inhibit_evaluation_warnings; @@ -2032,6 +2056,7 @@ extern GTY(()) struct saved_scope *scope_chain; #define in_discarded_stmt scope_chain->discarded_stmt #define in_consteval_if_p scope_chain->consteval_if_p +#define in_expansion_stmt scope_chain->expansion_stmt #define current_ref_temp_count scope_chain->ref_temp_count @@ -2206,6 +2231,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; @@ -2314,7 +2341,8 @@ enum languages { lang_c, lang_cplusplus }; /* Nonzero if NODE, a TYPE, has no name for linkage purposes. */ #define TYPE_UNNAMED_P(NODE) \ (TYPE_ANON_P (NODE) \ - && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE))) + && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \ + && !enum_with_enumerator_for_linkage_p (NODE)) /* The _DECL for this _TYPE. */ #define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE))) @@ -2352,6 +2380,10 @@ enum languages { lang_c, lang_cplusplus }; #define NON_UNION_CLASS_TYPE_P(T) \ (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T)) +/* Nonzero if T is a class type and is a union. */ +#define UNION_TYPE_P(T) \ + (TREE_CODE (T) == UNION_TYPE && TYPE_LANG_FLAG_5 (T)) + /* Keep these checks in ascending code order. */ #define RECORD_OR_UNION_CODE_P(T) \ ((T) == RECORD_TYPE || (T) == UNION_TYPE) @@ -2489,15 +2521,23 @@ struct GTY(()) lang_type { unsigned unique_obj_representations_set : 1; bool erroneous : 1; bool non_pod_aggregate : 1; + bool non_aggregate_pod : 1; + bool trivially_relocatable : 1; + bool trivially_relocatable_computed : 1; + + bool replaceable : 1; + bool replaceable_computed : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If - so, make sure to copy it in instantiate_class_template! */ + so, make sure to copy it in instantiate_class_template! + + Also make sure new flags here are streamed in module.cc. */ /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 3; + unsigned dummy : 30; tree primary_base; vec<tree_pair_s, va_gc> *vcall_indices; @@ -2508,15 +2548,19 @@ struct GTY(()) lang_type { vec<tree, va_gc> *pure_virtuals; tree friend_classes; vec<tree, va_gc> * GTY((reorder ("resort_type_member_vec"))) members; + /* CLASSTYPE_KEY_METHOD for TYPE_POLYMORPHIC_P types, CLASSTYPE_LAMBDA_EXPR + otherwise. */ tree key_method; tree decl_list; tree befriending_classes; - /* In a RECORD_TYPE, information specific to Objective-C++, such - as a list of adopted protocols or a pointer to a corresponding - @interface. See objc/objc-act.h for details. */ - tree objc_info; - /* FIXME reuse another field? */ - tree lambda_expr; + union maybe_objc_info { + /* If not c_dialect_objc, this part is not even allocated. */ + char GTY((tag ("0"))) non_objc; + /* In a RECORD_TYPE, information specific to Objective-C, such + as a list of adopted protocols or a pointer to a corresponding + @interface. See objc/objc-act.h for details. */ + tree GTY((tag ("1"))) objc_info; + } GTY ((desc ("c_dialect_objc ()"))) info; }; /* We used to have a variant type for lang_type. Keep the name of the @@ -2631,7 +2675,13 @@ struct GTY(()) lang_type { /* The member function with which the vtable will be emitted: the first noninline non-pure-virtual member function. NULL_TREE if there is no key function or if this is a class template */ -#define CLASSTYPE_KEY_METHOD(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->key_method) +#define CLASSTYPE_KEY_METHOD(NODE) \ + (TYPE_POLYMORPHIC_P (NODE) \ + ? LANG_TYPE_CLASS_CHECK (NODE)->key_method \ + : NULL_TREE) +#define SET_CLASSTYPE_KEY_METHOD(NODE, VALUE) \ + (gcc_checking_assert (TYPE_POLYMORPHIC_P (NODE)), \ + LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE)) /* Vector of members. During definition, it is unordered and only member functions are present. After completion it is sorted and @@ -2763,7 +2813,12 @@ struct GTY(()) lang_type { /* The associated LAMBDA_EXPR that made this class. */ #define CLASSTYPE_LAMBDA_EXPR(NODE) \ - (LANG_TYPE_CLASS_CHECK (NODE)->lambda_expr) + (TYPE_POLYMORPHIC_P (NODE) \ + ? NULL_TREE \ + : LANG_TYPE_CLASS_CHECK (NODE)->key_method) +#define SET_CLASSTYPE_LAMBDA_EXPR(NODE, VALUE) \ + (gcc_checking_assert (!TYPE_POLYMORPHIC_P (NODE)), \ + LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE)) /* The extra mangling scope for this closure type. */ #define LAMBDA_TYPE_EXTRA_SCOPE(NODE) \ (LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (NODE))) @@ -2824,6 +2879,34 @@ 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) + +/* If CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, true if this class is + trivially relocatable. + If !CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, true if this class + is marked with trivially_relocatable_if_eligible conditional keyword. */ +#define CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable) + +/* True if whether this class is trivially relocatable or not + has been computed already. */ +#define CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable_computed) + +/* If CLASSTYPE_REPLACEABLE_COMPUTED, true if this class is replaceable. + If !CLASSTYPE_REPLACEABLE_COMPUTED, true if this class is marked with + replaceable_if_eligible conditional keyword. */ +#define CLASSTYPE_REPLACEABLE_BIT(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->replaceable) + +/* True if whether this class is replaceable or not has been computed + already. */ +#define CLASSTYPE_REPLACEABLE_COMPUTED(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->replaceable_computed) /* Additional macros for inheritance information. */ @@ -2967,7 +3050,10 @@ struct GTY(()) lang_decl_base { unsigned module_keyed_decls_p : 1; /* has keys, applies to all decls */ - /* 11 spare bits. */ + /* VAR_DECL being used to represent an OpenMP declared mapper. */ + unsigned omp_declare_mapper_p : 1; + + /* 10 spare bits. */ }; /* True for DECL codes which have template info and access. */ @@ -2996,6 +3082,8 @@ struct GTY(()) lang_decl_min { In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE. In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL, this is DECL_DISCRIMINATOR. + In constexpr exception artificial VAR_DECL, this is + DECL_EXCEPTION_REFCOUNT. In a DECL_LOCAL_DECL_P decl, this is the namespace decl it aliases. Otherwise, in a class-scope DECL, this is DECL_ACCESS. */ tree access; @@ -4450,6 +4538,23 @@ get_vec_init_expr (tree t) #define MUST_NOT_THROW_COND(NODE) \ TREE_OPERAND (MUST_NOT_THROW_EXPR_CHECK (NODE), 1) +/* Reasons why MUST_NOT_THROW_EXPR has been created. */ + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap body of + a noexcept function. */ +#define MUST_NOT_THROW_NOEXCEPT_P(NODE) \ + TREE_LANG_FLAG_0 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of + exception object during throw. */ +#define MUST_NOT_THROW_THROW_P(NODE) \ + TREE_LANG_FLAG_1 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + +/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of + handler parameter during catch. */ +#define MUST_NOT_THROW_CATCH_P(NODE) \ + TREE_LANG_FLAG_2 (MUST_NOT_THROW_EXPR_CHECK (NODE)) + /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a TEMPLATE_DECL. This macro determines whether or not a given class type is really a template type, as opposed to an instantiation or @@ -4470,11 +4575,14 @@ get_vec_init_expr (tree t) #define TYPENAME_IS_ENUM_P(NODE) \ (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE))) -/* True if a TYPENAME_TYPE was declared as a "class", "struct", or - "union". */ +/* True if a TYPENAME_TYPE was declared as a "class" or "struct". */ #define TYPENAME_IS_CLASS_P(NODE) \ (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE))) +/* True if a TYPENAME_TYPE was declared as a "union". */ +#define TYPENAME_IS_UNION_P(NODE) \ + (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE))) + /* True if a TYPENAME_TYPE is in the process of being resolved. */ #define TYPENAME_IS_RESOLVING_P(NODE) \ (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE))) @@ -4489,7 +4597,7 @@ get_vec_init_expr (tree t) #define TYPE_CONTAINS_VPTR_P(NODE) \ (TYPE_POLYMORPHIC_P (NODE) || CLASSTYPE_VBASECLASSES (NODE)) -/* Nonzero if NODE is a FUNCTION_DECL or VARIABLE_DECL (for a decl +/* Nonzero if NODE is a FUNCTION_DECL or VAR_DECL (for a decl with namespace scope) declared in a local scope. */ #define DECL_LOCAL_DECL_P(NODE) \ DECL_LANG_FLAG_0 (VAR_OR_FUNCTION_DECL_CHECK (NODE)) @@ -4522,6 +4630,11 @@ get_vec_init_expr (tree t) #define DECL_OMP_DECLARE_REDUCTION_P(NODE) \ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p) +/* Nonzero if NODE is an artificial FUNCTION_DECL for + #pragma omp declare mapper. */ +#define DECL_OMP_DECLARE_MAPPER_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.omp_declare_mapper_p) + /* Nonzero if DECL has been declared threadprivate by #pragma omp threadprivate. */ #define CP_DECL_THREADPRIVATE_P(DECL) \ @@ -5125,6 +5238,10 @@ get_vec_init_expr (tree t) protected_access_node will appear in the DECL_ACCESS for the node. */ #define DECL_ACCESS(NODE) (LANG_DECL_MIN_CHECK (NODE)->access) +/* In artificial VAR_DECL created by cxa_allocate_exception + this is reference count. */ +#define DECL_EXCEPTION_REFCOUNT(NODE) (LANG_DECL_MIN_CHECK (NODE)->access) + /* Nonzero if the FUNCTION_DECL is a global constructor. */ #define DECL_GLOBAL_CTOR_P(NODE) \ (LANG_DECL_FN_CHECK (NODE)->global_ctor_p) @@ -5514,6 +5631,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) \ @@ -5582,6 +5703,19 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) #define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_5 (RANGE_FOR_STMT_CHECK (NODE)) +/* TEMPLATE_FOR_STMT accessors. These give access to the declarator, + expression, body, and scope of the statement, respectively. */ +#define TEMPLATE_FOR_DECL(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 0) +#define TEMPLATE_FOR_EXPR(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 1) +#define TEMPLATE_FOR_BODY(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 2) +#define TEMPLATE_FOR_SCOPE(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 3) +#define TEMPLATE_FOR_INIT_STMT(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 4) + /* STMT_EXPR accessor. */ #define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) @@ -6439,7 +6573,9 @@ enum virt_specifier { VIRT_SPEC_UNSPECIFIED = 0x0, VIRT_SPEC_FINAL = 0x1, - VIRT_SPEC_OVERRIDE = 0x2 + VIRT_SPEC_OVERRIDE = 0x2, + VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE = 0x4, + VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE = 0x8 }; /* A type-qualifier, or bitmask therefore, using the VIRT_SPEC @@ -6691,9 +6827,11 @@ struct GTY((chain_next ("%h.next"))) tinst_level { /* The original node. TLDCL can be a DECL (for a function or static data member), a TYPE (for a class), depending on what we were - asked to instantiate, or a TREE_LIST with the template as PURPOSE - and the template args as VALUE, if we are substituting for - overload resolution. In all these cases, TARGS is NULL. + asked to instantiate, a TEMPLATE_FOR_STMT (for instantiation + of expansion stmt body outside of templates) or a TREE_LIST with + the template as PURPOSE and the template args as VALUE, if we are + substituting for overload resolution. In all these cases, TARGS + is NULL. However, to avoid creating TREE_LIST objects for substitutions if we can help, we store PURPOSE and VALUE in TLDCL and TARGS, respectively. So TLDCL stands for TREE_LIST or DECL (the @@ -6753,8 +6891,14 @@ struct GTY((chain_next ("%h.next"))) tinst_level { /* The location where the template is instantiated. */ location_t locus; - /* errorcount + sorrycount when we pushed this level. */ - unsigned short errors; + /* errorcount + sorrycount when we pushed this level. If the value + overflows, it will always seem like we currently have more errors, so we + will limit template recursion even from non-erroneous templates. In a TU + with over 32k errors, that's fine. */ + unsigned short errors : 15; + + /* set in pop_tinst_level if there have been errors since we pushed. */ + bool had_errors : 1; /* Count references to this object. If refcount reaches refcount_infinity value, we don't increment or decrement the @@ -6775,6 +6919,7 @@ enum cp_built_in_function { CP_BUILT_IN_IS_CORRESPONDING_MEMBER, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, + CP_BUILT_IN_EH_PTR_ADJUST_REF, CP_BUILT_IN_LAST }; @@ -6808,6 +6953,7 @@ extern int class_dump_id; extern int module_dump_id; extern int raw_dump_id; extern int coro_dump_id; +extern int tinst_dump_id; /* Whether the current context is manifestly constant-evaluated. Used by the constexpr machinery to control folding of @@ -6954,6 +7100,7 @@ extern bool type_has_extended_temps (tree); extern tree strip_top_quals (tree); extern bool reference_related_p (tree, tree); extern bool reference_compatible_p (tree, tree); +extern bool handler_match_for_exception_type (tree, tree); extern int remaining_arguments (tree); extern tree build_implicit_conv_flags (tree, tree, int); extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t); @@ -7042,6 +7189,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 +7220,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 */ @@ -7122,7 +7271,7 @@ extern void determine_local_discriminator (tree, tree = NULL_TREE); extern bool member_like_constrained_friend_p (tree); extern bool fns_correspond (tree, tree); extern int decls_match (tree, tree, bool = true); -extern bool maybe_version_functions (tree, tree, bool); +extern bool maybe_version_functions (tree, tree); extern bool validate_constexpr_redeclaration (tree, tree); extern bool merge_default_template_args (tree, tree, bool); extern tree duplicate_decls (tree, tree, @@ -7156,6 +7305,7 @@ extern void omp_declare_variant_finalize (tree, tree); struct cp_decomp { tree decl; unsigned int count; }; extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr); extern tree lookup_decomp_type (tree); +HOST_WIDE_INT cp_decomp_size (location_t, tree, tsubst_flags_t); extern bool cp_finish_decomp (tree, cp_decomp *, bool = false); extern int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); @@ -7176,6 +7326,7 @@ extern tree xref_tag (tag_types, tree, bool tpl_header_p = false); extern void xref_basetypes (tree, tree); extern tree start_enum (tree, tree, tree, tree, bool, bool *); +extern bool enum_with_enumerator_for_linkage_p (tree); extern void finish_enum_value_list (tree); extern void finish_enum (tree); extern tree build_enumerator (tree, tree, tree, tree, location_t); @@ -7307,6 +7458,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); @@ -7322,7 +7496,7 @@ extern void maybe_warn_variadic_templates (void); extern void maybe_warn_cpp0x (cpp0x_warn_str str, location_t = input_location); extern bool pedwarn_cxx98 (location_t, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, @@ -7348,6 +7522,7 @@ extern int nothrow_libfn_p (const_tree); extern void check_handlers (tree); extern tree finish_noexcept_expr (tree, tsubst_flags_t); extern bool expr_noexcept_p (tree, tsubst_flags_t); +extern void explain_not_noexcept (tree); extern void perform_deferred_noexcept_checks (void); extern bool nothrow_spec_p (const_tree); extern bool type_noexcept_p (const_tree); @@ -7469,11 +7644,14 @@ extern void finish_thunk (tree); extern void use_thunk (tree, bool); extern bool trivial_fn_p (tree); extern tree forward_parm (tree); -extern bool is_trivially_xible (enum tree_code, tree, tree); -extern bool is_nothrow_xible (enum tree_code, tree, tree); -extern bool is_xible (enum tree_code, tree, tree); -extern bool is_convertible (tree, tree); -extern bool is_nothrow_convertible (tree, tree); +extern bool is_trivially_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_nothrow_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_xible (enum tree_code, tree, tree, + bool = false); +extern bool is_convertible (tree, tree, bool = false); +extern bool is_nothrow_convertible (tree, tree, bool = false); extern bool ref_xes_from_temporary (tree, tree, bool); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern bool maybe_explain_implicit_delete (tree); @@ -7502,6 +7680,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; } @@ -7609,8 +7789,12 @@ extern tree clone_attrs (tree); extern bool maybe_clone_body (tree); /* In parser.cc */ +extern tree cp_build_range_for_decls (location_t, tree, tree *, bool); extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, tree, bool); +extern tree build_range_temp (tree); +extern tree cp_perform_range_for_lookup (tree, tree *, tree *, + tsubst_flags_t = tf_warning_or_error); extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &, bool); @@ -7618,12 +7802,13 @@ 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); extern bool literal_integer_zerop (const_tree); extern tree attr_chainon (tree, tree); +extern tree maybe_add_dummy_lambda_op (tree); +extern void remove_dummy_lambda_op (tree, tree); /* in pt.cc */ extern tree canonical_type_parameter (tree); @@ -7759,6 +7944,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); @@ -7827,6 +8013,7 @@ extern tree add_to_template_args (tree, tree); extern tree add_outermost_template_args (tree, tree); extern tree add_extra_args (tree, tree, tsubst_flags_t, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); +extern void finish_expansion_stmt (tree, tree, tsubst_flags_t, tree); /* in rtti.cc */ /* A vector of all tinfo decls that haven't been emitted yet. */ @@ -7906,6 +8093,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. */ @@ -7926,6 +8114,7 @@ public: extern int stmts_are_full_exprs_p (void); extern void init_cp_semantics (void); extern tree do_poplevel (tree); +extern tree do_pushlevel (scope_kind); extern void break_maybe_infinite_loop (void); extern void add_decl_expr (tree); extern tree maybe_cleanup_point_expr_void (tree); @@ -7952,7 +8141,7 @@ extern void find_range_for_decls (tree[3]); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); extern void finish_range_for_decl (tree, tree, tree); -extern void finish_range_for_stmt (tree); +extern tree begin_template_for_scope (tree *); extern tree finish_break_stmt (void); extern tree finish_continue_stmt (void); extern tree begin_switch_stmt (void); @@ -8054,11 +8243,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> &); @@ -8098,10 +8290,11 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool, bool); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, - bool, bool); + bool, bool, bool = false); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); +extern tree finish_structured_binding_size (location_t, tree, tsubst_flags_t); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree finish_trait_type (enum cp_trait_kind, tree, tree, tsubst_flags_t); extern tree build_lambda_expr (void); @@ -8123,7 +8316,7 @@ extern void register_capture_members (tree); extern tree lambda_expr_this_capture (tree, int); extern void maybe_generic_this_capture (tree, tree); extern tree maybe_resolve_dummy (tree, bool); -extern tree current_nonlambda_function (void); +extern tree current_nonlambda_function (bool = false); extern tree nonlambda_method_basetype (void); extern tree current_nonlambda_scope (bool = false); extern tree current_lambda_expr (void); @@ -8146,6 +8339,7 @@ extern void record_lambda_scope (tree lambda); extern void record_lambda_scope_discriminator (tree lambda); extern void record_lambda_scope_sig_discriminator (tree lambda, tree fn); extern tree start_lambda_function (tree fn, tree lambda_expr); +extern void push_capture_proxies (tree, bool = false); extern void finish_lambda_function (tree body); extern bool regenerated_lambda_fn_p (tree); extern tree lambda_regenerating_args (tree); @@ -8173,6 +8367,8 @@ extern bool pod_type_p (const_tree); extern bool layout_pod_type_p (const_tree); extern bool std_layout_type_p (const_tree); extern bool trivial_type_p (const_tree); +extern bool trivially_relocatable_type_p (tree); +extern bool replaceable_type_p (tree); extern bool trivially_copyable_p (const_tree); extern bool type_has_unique_obj_representations (const_tree); extern bool scalarish_type_p (const_tree); @@ -8318,9 +8514,9 @@ extern void cxx_print_xnode (FILE *, tree, int); extern void cxx_print_decl (FILE *, tree, int); extern void cxx_print_type (FILE *, tree, int); extern void cxx_print_identifier (FILE *, tree, int); -extern void cxx_print_error_function (diagnostic_text_output_format &, +extern void cxx_print_error_function (diagnostics::text_sink &, const char *, - const diagnostic_info *); + const diagnostics::diagnostic_info *); /* in typeck.cc */ /* Says how we should behave when comparing two arrays one of which @@ -8507,7 +8703,7 @@ extern void maybe_warn_pessimizing_move (tree, tree, bool); /* in typeck2.cc */ extern void require_complete_eh_spec_types (tree, tree); extern bool cxx_incomplete_type_diagnostic (location_t, const_tree, - const_tree, diagnostic_t); + const_tree, enum diagnostics::kind); inline location_t loc_or_input_loc (location_t loc) { @@ -8555,7 +8751,7 @@ cp_expr_loc_or_input_loc (const_tree t) inline bool cxx_incomplete_type_diagnostic (const_tree value, const_tree type, - diagnostic_t diag_kind) + enum diagnostics::kind diag_kind) { return cxx_incomplete_type_diagnostic (cp_expr_loc_or_input_loc (value), value, type, diag_kind); @@ -8566,7 +8762,7 @@ extern void cxx_incomplete_type_error (location_t, const_tree, inline void cxx_incomplete_type_error (const_tree value, const_tree type) { - cxx_incomplete_type_diagnostic (value, type, DK_ERROR); + cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error); } extern void cxx_incomplete_type_inform (const_tree); @@ -8637,7 +8833,7 @@ extern alias_set_type cxx_get_alias_set (tree); extern bool cxx_warn_unused_global_decl (const_tree); extern size_t cp_tree_size (enum tree_code); extern bool cp_var_mod_type_p (tree, tree); -extern void cxx_initialize_diagnostics (diagnostic_context *); +extern void cxx_initialize_diagnostics (diagnostics::context *); extern int cxx_types_compatible_p (tree, tree); extern bool cxx_block_may_fallthru (const_tree); @@ -8654,6 +8850,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); @@ -8778,9 +8978,12 @@ extern bool constraints_equivalent_p (tree, tree); extern bool atomic_constraints_identical_p (tree, tree); extern hashval_t iterative_hash_constraint (tree, hashval_t); extern hashval_t hash_atomic_constraint (tree); +extern void diagnose_trait_expr (location_t, tree, tree); +extern bool maybe_diagnose_standard_trait (location_t, tree); extern void diagnose_constraints (location_t, tree, tree); -extern void note_failed_type_completion_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 +9040,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 +9051,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/cvt.cc b/gcc/cp/cvt.cc index f663a6d..55be12d 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1186,13 +1186,6 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) expr = maybe_undo_parenthesized_ref (expr); - expr = mark_discarded_use (expr); - if (implicit == ICV_CAST) - /* An explicit cast to void avoids all -Wunused-but-set* warnings. */ - mark_exp_read (expr); - - if (!TREE_TYPE (expr)) - return expr; if (invalid_nonstatic_memfn_p (loc, expr, complain)) return error_mark_node; if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR) @@ -1209,6 +1202,12 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) if (VOID_TYPE_P (TREE_TYPE (expr))) return expr; + + expr = mark_discarded_use (expr); + if (implicit == ICV_CAST) + /* An explicit cast to void avoids all -Wunused-but-set* warnings. */ + mark_exp_read (expr); + switch (TREE_CODE (expr)) { case COND_EXPR: diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index cf301bd..4916bf6 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); @@ -2138,6 +2137,29 @@ cxx_pretty_printer::statement (tree t) pp_needs_newline (this) = true; break; + case TEMPLATE_FOR_STMT: + pp_cxx_ws_string (this, "template for"); + pp_space (this); + pp_cxx_left_paren (this); + if (TEMPLATE_FOR_INIT_STMT (t)) + { + statement (TEMPLATE_FOR_INIT_STMT (t)); + pp_needs_newline (this) = false; + pp_cxx_whitespace (this); + } + statement (TEMPLATE_FOR_DECL (t)); + pp_space (this); + pp_needs_newline (this) = false; + pp_colon (this); + pp_space (this); + statement (TEMPLATE_FOR_EXPR (t)); + pp_cxx_right_paren (this); + pp_newline_and_indent (this, 3); + statement (TEMPLATE_FOR_BODY (t)); + pp_indentation (this) -= 3; + pp_needs_newline (this) = true; + break; + /* expression-statement: expression(opt) ; */ case EXPR_STMT: @@ -2954,5 +2976,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..4b1a335 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -110,7 +110,7 @@ static void initialize_local_var (tree, tree, bool); static void expand_static_init (tree, tree); static location_t smallest_type_location (const cp_decl_specifier_seq*); static bool identify_goto (tree, location_t, const location_t *, - diagnostic_t, bool); + enum diagnostics::kind, bool); /* The following symbols are subsumed in the cp_global_trees array, and listed here individually for documentation purposes. @@ -572,9 +572,9 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) ent->in_stmt_expr = true; break; case sk_block: - if (level_for_constexpr_if (bl->level_chain)) + if (level_for_constexpr_if (obl)) ent->in_constexpr_if = true; - else if (level_for_consteval_if (bl->level_chain)) + else if (level_for_consteval_if (obl)) ent->in_consteval_if = true; break; default: @@ -747,11 +747,11 @@ poplevel (int keep, int reverse, int functionbody) { if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl)) warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wunused_but_set_variable, "structured " + OPT_Wunused_but_set_variable_, "structured " "binding declaration set but not used"); else warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wunused_but_set_variable, + OPT_Wunused_but_set_variable_, "variable %qD set but not used", decl); unused_but_set_errorcount = errorcount; } @@ -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; } @@ -1216,9 +1214,7 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) && targetm.target_option.function_versions (newdecl, olddecl)) { if (record_versions) - maybe_version_functions (newdecl, olddecl, - (!DECL_FUNCTION_VERSIONED (newdecl) - || !DECL_FUNCTION_VERSIONED (olddecl))); + maybe_version_functions (newdecl, olddecl); return 0; } } @@ -1285,11 +1281,11 @@ maybe_mark_function_versioned (tree decl) } /* NEWDECL and OLDDECL have identical signatures. If they are - different versions adjust them and return true. - If RECORD is set to true, record function versions. */ + different versions adjust them, record function versions, and return + true. */ bool -maybe_version_functions (tree newdecl, tree olddecl, bool record) +maybe_version_functions (tree newdecl, tree olddecl) { if (!targetm.target_option.function_versions (newdecl, olddecl)) return false; @@ -1312,8 +1308,13 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record) maybe_mark_function_versioned (newdecl); } - if (record) - cgraph_node::record_function_versions (olddecl, newdecl); + /* Add the new version to the function version structure. */ + cgraph_node *fn_node = cgraph_node::get_create (olddecl); + cgraph_function_version_info *fn_v = fn_node->function_version (); + if (!fn_v) + fn_v = fn_node->insert_new_function_version (); + + cgraph_node::add_function_version (fn_v, newdecl); return true; } @@ -2008,8 +2009,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) } /* For function versions, params and types match, but they are not ambiguous. */ - else if ((!DECL_FUNCTION_VERSIONED (newdecl) - && !DECL_FUNCTION_VERSIONED (olddecl)) + else if (((!DECL_FUNCTION_VERSIONED (newdecl) + && !DECL_FUNCTION_VERSIONED (olddecl)) + || !same_type_p (fndecl_declared_return_type (newdecl), + fndecl_declared_return_type (olddecl))) /* Let constrained hidden friends coexist for now, we'll check satisfaction later. */ && !member_like_constrained_friend_p (newdecl) @@ -3734,10 +3737,10 @@ decl_jump_unsafe (tree decl) static bool identify_goto (tree decl, location_t loc, const location_t *locus, - diagnostic_t diag_kind, bool computed) + enum diagnostics::kind diag_kind, bool computed) { if (computed) - diag_kind = DK_WARNING; + diag_kind = diagnostics::kind::warning; bool complained = emit_diagnostic (diag_kind, loc, 0, decl ? G_("jump to label %qD") @@ -3773,7 +3776,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (exited_omp) { - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); if (complained) inform (input_location, " exits OpenMP structured block"); @@ -3795,7 +3799,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (!identified) { - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; } @@ -3863,7 +3868,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (inf) { if (identified < 2) - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; if (complained) @@ -3874,7 +3880,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, if (!vec_safe_is_empty (computed)) { if (!identified) - complained = identify_goto (decl, input_location, locus, DK_ERROR, + complained = identify_goto (decl, input_location, locus, + diagnostics::kind::error, computed); identified = 2; if (complained) @@ -3946,14 +3953,14 @@ check_goto_1 (named_label_entry *ent, bool computed) || ent->in_omp_scope || ent->in_stmt_expr || !vec_safe_is_empty (ent->bad_decls)) { - diagnostic_t diag_kind = DK_PERMERROR; + enum diagnostics::kind diag_kind = diagnostics::kind::permerror; if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if || ent->in_consteval_if || ent->in_transaction_scope || ent->in_omp_scope || ent->in_stmt_expr) - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), &input_location, diag_kind, computed); - identified = 1 + (diag_kind == DK_ERROR); + identified = 1 + (diag_kind == diagnostics::kind::error); } FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad) @@ -3966,7 +3973,9 @@ check_goto_1 (named_label_entry *ent, bool computed) if (identified == 1) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, + diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -4010,7 +4019,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, + &input_location, + diagnostics::kind::error, computed); identified = 2; } @@ -4034,7 +4044,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -4050,7 +4061,8 @@ check_goto_1 (named_label_entry *ent, bool computed) { complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), - &input_location, DK_ERROR, computed); + &input_location, diagnostics::kind::error, + computed); identified = 2; } if (complained) @@ -4324,7 +4336,19 @@ finish_case_label (location_t loc, tree low_value, tree high_value) tree label; /* For templates, just add the case label; we'll do semantic - analysis at instantiation-time. */ + analysis at instantiation-time. But diagnose case labels + in expansion statements with switch outside of it here. */ + if (in_expansion_stmt) + for (cp_binding_level *b = current_binding_level; + b != switch_stack->level; b = b->level_chain) + if (b->kind == sk_template_for && b->this_entity) + { + auto_diagnostic_group d; + error ("jump to case label"); + inform (EXPR_LOCATION (b->this_entity), + " enters %<template for%> statement"); + return error_mark_node; + } label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node); return add_stmt (build_case_label (low_value, high_value, label)); } @@ -4362,6 +4386,7 @@ struct typename_info { tree template_id; bool enum_p; bool class_p; + bool union_p; }; struct typename_hasher : ggc_ptr_hash<tree_node> @@ -4400,7 +4425,8 @@ struct typename_hasher : ggc_ptr_hash<tree_node> && TYPE_CONTEXT (t1) == t2->scope && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id && TYPENAME_IS_ENUM_P (t1) == t2->enum_p - && TYPENAME_IS_CLASS_P (t1) == t2->class_p); + && TYPENAME_IS_CLASS_P (t1) == t2->class_p + && TYPENAME_IS_UNION_P (t1) == t2->union_p); } }; @@ -4424,9 +4450,8 @@ build_typename_type (tree context, tree name, tree fullname, ti.name = name; ti.template_id = fullname; ti.enum_p = tag_type == enum_type; - ti.class_p = (tag_type == class_type - || tag_type == record_type - || tag_type == union_type); + ti.class_p = (tag_type == class_type || tag_type == record_type); + ti.union_p = tag_type == union_type; hashval_t hash = typename_hasher::hash (&ti); /* See if we already have this type. */ @@ -4442,6 +4467,7 @@ build_typename_type (tree context, tree name, tree fullname, TYPENAME_TYPE_FULLNAME (t) = ti.template_id; TYPENAME_IS_ENUM_P (t) = ti.enum_p; TYPENAME_IS_CLASS_P (t) = ti.class_p; + TYPENAME_IS_UNION_P (t) = ti.union_p; /* Build the corresponding TYPE_DECL. */ tree d = build_decl (input_location, TYPE_DECL, name, t); @@ -5072,6 +5098,18 @@ cxx_init_decl_processing (void) BUILT_IN_FRONTEND, NULL, NULL_TREE); set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + if (cxx_dialect >= cxx26) + { + tree void_ptrintftype + = build_function_type_list (void_type_node, ptr_type_node, + integer_type_node, NULL_TREE); + decl = add_builtin_function ("__builtin_eh_ptr_adjust_ref", + void_ptrintftype, + CP_BUILT_IN_EH_PTR_ADJUST_REF, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF); + } + integer_two_node = build_int_cst (NULL_TREE, 2); /* Guess at the initial static decls size. */ @@ -5339,6 +5377,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 +6238,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 +7917,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)) { @@ -8555,6 +8607,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr) variant = cp_get_callee_fndecl_nofold (STRIP_REFERENCE_REF (variant)); input_location = save_loc; + if (variant == decl) + { + error_at (varid_loc, "variant %qD is the same as base function", + variant); + return true; + } + if (variant) { bool fail; @@ -8897,13 +8956,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, TREE_TYPE (decl) = error_mark_node; return; } + + /* Now that we have a type, try these again. */ + layout_decl (decl, 0); cp_apply_type_quals_to_decl (cp_type_quals (type), decl); /* Update the type of the corresponding TEMPLATE_DECL to match. */ - if (DECL_LANG_SPECIFIC (decl) - && DECL_TEMPLATE_INFO (decl) - && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) == decl) - TREE_TYPE (DECL_TI_TEMPLATE (decl)) = type; + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)) + { + tree tmpl = template_for_substitution (decl); + if (DECL_TEMPLATE_RESULT (tmpl) == decl) + TREE_TYPE (tmpl) = type; + } } if (ensure_literal_type_for_constexpr_object (decl) == error_mark_node) @@ -9147,6 +9211,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (decomp) { + if (DECL_DECLARED_CONSTINIT_P (decl) && cxx_dialect < cxx26) + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions, + "%<constinit%> can be applied to structured binding " + "only with %<-std=c++2c%> or %<-std=gnu++2c%>"); cp_maybe_mangle_decomp (decl, decomp); if (TREE_STATIC (decl) && !DECL_FUNCTION_SCOPE_P (decl)) { @@ -9188,14 +9256,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); @@ -9575,13 +9652,17 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, error has been diagnosed. */ static tree -find_decomp_class_base (location_t loc, tree type, tree ret) +find_decomp_class_base (location_t loc, tree type, tree ret, + tsubst_flags_t complain) { if (LAMBDA_TYPE_P (type)) { - auto_diagnostic_group d; - error_at (loc, "cannot decompose lambda closure type %qT", type); - inform (location_of (type), "lambda declared here"); + if (complain & tf_error) + { + auto_diagnostic_group d; + error_at (loc, "cannot decompose lambda closure type %qT", type); + inform (location_of (type), "lambda declared here"); + } return error_mark_node; } @@ -9595,6 +9676,8 @@ find_decomp_class_base (location_t loc, tree type, tree ret) return type; else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) { + if ((complain & tf_error) == 0) + return error_mark_node; auto_diagnostic_group d; if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) error_at (loc, "cannot decompose class type %qT because it has an " @@ -9607,6 +9690,8 @@ find_decomp_class_base (location_t loc, tree type, tree ret) } else if (!accessible_p (type, field, true)) { + if ((complain & tf_error) == 0) + return error_mark_node; auto_diagnostic_group d; error_at (loc, "cannot decompose inaccessible member %qD of %qT", field, type); @@ -9628,28 +9713,32 @@ find_decomp_class_base (location_t loc, tree type, tree ret) BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { auto_diagnostic_group d; - tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret); + tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret, + complain); if (t == error_mark_node) { - inform (location_of (type), "in base class of %qT", type); + if (complain & tf_error) + inform (location_of (type), "in base class of %qT", type); return error_mark_node; } if (t != NULL_TREE && t != ret) { if (ret == type) { - error_at (loc, "cannot decompose class type %qT: both it and " - "its base class %qT have non-static data members", - type, t); + if (complain & tf_error) + error_at (loc, "cannot decompose class type %qT: both it and " + "its base class %qT have non-static data " + "members", type, t); return error_mark_node; } else if (orig_ret != NULL_TREE) return t; else if (ret != NULL_TREE) { - error_at (loc, "cannot decompose class type %qT: its base " - "classes %qT and %qT have non-static data " - "members", type, ret, t); + if (complain & tf_error) + error_at (loc, "cannot decompose class type %qT: its base " + "classes %qT and %qT have non-static data " + "members", type, ret, t); return error_mark_node; } else @@ -9680,7 +9769,7 @@ get_tuple_size (tree type) if (val == error_mark_node) return NULL_TREE; if (VAR_P (val) || TREE_CODE (val) == CONST_DECL) - val = maybe_constant_value (val); + val = maybe_constant_value (val, NULL_TREE, mce_true); if (TREE_CODE (val) == INTEGER_CST) return val; else @@ -9690,7 +9779,7 @@ get_tuple_size (tree type) /* Return std::tuple_element<I,TYPE>::type. */ static tree -get_tuple_element_type (tree type, unsigned i) +get_tuple_element_type (tree type, unsigned HOST_WIDE_INT i) { tree args = make_tree_vec (2); TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); @@ -9706,7 +9795,7 @@ get_tuple_element_type (tree type, unsigned i) /* Return e.get<i>() or get<i>(e). */ static tree -get_tuple_decomp_init (tree decl, unsigned i) +get_tuple_decomp_init (tree decl, unsigned HOST_WIDE_INT i) { tree targs = make_tree_vec (1); TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i); @@ -9812,6 +9901,134 @@ cp_maybe_mangle_decomp (tree decl, cp_decomp *decomp) } } +/* Append #i to DECL_NAME (decl) or for name independent decls + clear DECL_NAME (decl). */ + +static void +set_sb_pack_name (tree decl, unsigned HOST_WIDE_INT i) +{ + if (name_independent_decl_p (decl)) + /* Only "_" names are treated as name independent, "_#0" etc. is not and + because we pushdecl the individual decl elements of structured binding + pack, we could get redeclaration errors if there are 2 or more name + independent structured binding packs in the same scope. */ + DECL_NAME (decl) = NULL_TREE; + else + { + tree name = DECL_NAME (decl); + size_t len = IDENTIFIER_LENGTH (name) + 22; + char *n = XALLOCAVEC (char, len); + snprintf (n, len, "%s#" HOST_WIDE_INT_PRINT_UNSIGNED, + IDENTIFIER_POINTER (name), i); + DECL_NAME (decl) = get_identifier (n); + } +} + +/* Return structured binding size of TYPE or -1 if erroneous. */ + +HOST_WIDE_INT +cp_decomp_size (location_t loc, tree type, tsubst_flags_t complain) +{ + if (TYPE_REF_P (type)) + { + type = complete_type (TREE_TYPE (type)); + if (type == error_mark_node) + return -1; + if (!COMPLETE_TYPE_P (type)) + { + if (complain & tf_error) + error_at (loc, "structured binding refers to incomplete type %qT", + type); + return -1; + } + } + + unsigned HOST_WIDE_INT eltscnt = 0; + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (TYPE_DOMAIN (type) == NULL_TREE) + { + if (complain & tf_error) + error_at (loc, "cannot decompose array of unknown bound %qT", + type); + return -1; + } + tree nelts = array_type_nelts_top (type); + if (nelts == error_mark_node) + return -1; + if (!tree_fits_shwi_p (nelts)) + { + if (complain & tf_error) + error_at (loc, "cannot decompose variable length array %qT", type); + return -1; + } + return tree_to_shwi (nelts); + } + /* 2 GNU extensions. */ + else if (TREE_CODE (type) == COMPLEX_TYPE) + return 2; + else if (TREE_CODE (type) == VECTOR_TYPE) + { + if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&eltscnt)) + { + if (complain & tf_error) + error_at (loc, "cannot decompose variable length vector %qT", type); + return -1; + } + return eltscnt; + } + else if (tree tsize = get_tuple_size (type)) + { + if (tsize == error_mark_node + || !tree_fits_shwi_p (tsize) + || tree_int_cst_sgn (tsize) < 0) + { + if (complain & tf_error) + error_at (loc, "%<std::tuple_size<%T>::value%> is not an integral " + "constant expression", type); + return -1; + } + return tree_to_shwi (tsize); + } + else if (TREE_CODE (type) == UNION_TYPE) + { + if (complain & tf_error) + error_at (loc, "cannot decompose union type %qT", type); + return -1; + } + else if (!CLASS_TYPE_P (type)) + { + if (complain & tf_error) + error_at (loc, "cannot decompose non-array non-class type %qT", type); + return -1; + } + else if (processing_template_decl && complete_type (type) == error_mark_node) + return -1; + else if (!COMPLETE_TYPE_P (type)) + { + if (complain & tf_error) + error_at (loc, "structured binding refers to incomplete class type " + "%qT", type); + return -1; + } + else + { + tree btype = find_decomp_class_base (loc, type, NULL_TREE, complain); + if (btype == error_mark_node) + return -1; + else if (btype == NULL_TREE) + return 0; + for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL + || DECL_ARTIFICIAL (field) + || DECL_UNNAMED_BIT_FIELD (field)) + continue; + else + eltscnt++; + return eltscnt; + } +} + /* Finish a decomposition declaration. DECL is the underlying declaration "e", FIRST is the head of a chain of decls for the individual identifiers chained through DECL_CHAIN in reverse order and COUNT is the number of @@ -9868,10 +10085,13 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) auto_vec<tree, 16> v; v.safe_grow (count, true); tree d = first; + int pack = -1; for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) { v[count - i - 1] = d; fit_decomposition_lang_decl (d, decl); + if (DECL_PACK_P (d)) + pack = count - i - 1; } tree type = TREE_TYPE (decl); @@ -9893,6 +10113,14 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) tree eltype = NULL_TREE; unsigned HOST_WIDE_INT eltscnt = 0; + /* Structured binding packs when initializer is non-dependent should + have their DECL_VALUE_EXPR set to a TREE_VEC. First two elements + of that TREE_VEC are the base and index, what is normally represented + as DECL_VALUE_EXPR ARRAY_REF <base, index> where index is the index + of the pack first element. The remaining elements of the TREE_VEC + are VAR_DECLs for the pack elements. */ + tree packv = NULL_TREE; + if (TREE_CODE (type) == ARRAY_TYPE) { tree nelts; @@ -9911,7 +10139,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) goto error_out; } eltscnt = tree_to_uhwi (nelts); - if (count != eltscnt) + if (pack != -1 ? count - 1 > eltscnt : count != eltscnt) { cnt_mismatch: auto_diagnostic_group d; @@ -9932,12 +10160,37 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) eltype = TREE_TYPE (type); for (unsigned int i = 0; i < count; i++) { + if ((unsigned) pack == i) + { + packv = make_tree_vec (eltscnt - count + 3); + for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j) + { + tree t; + TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]); + set_sb_pack_name (t, j); + maybe_push_decl (t); + TREE_TYPE (t) = eltype; + layout_decl (t, 0); + if (!processing_template_decl) + { + tree a = unshare_expr (dexp); + a = build4 (ARRAY_REF, eltype, a, size_int (j + pack), + NULL_TREE, NULL_TREE); + SET_DECL_VALUE_EXPR (t, a); + DECL_HAS_VALUE_EXPR_P (t) = 1; + } + } + continue; + } TREE_TYPE (v[i]) = eltype; layout_decl (v[i], 0); if (processing_template_decl) continue; tree t = unshare_expr (dexp); - t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE); + unsigned HOST_WIDE_INT j = i; + if (pack != -1 && (unsigned) pack < i) + j = i + eltscnt - count; + t = build4 (ARRAY_REF, eltype, t, size_int (j), NULL_TREE, NULL_TREE); SET_DECL_VALUE_EXPR (v[i], t); DECL_HAS_VALUE_EXPR_P (v[i]) = 1; } @@ -9946,17 +10199,41 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) else if (TREE_CODE (type) == COMPLEX_TYPE) { eltscnt = 2; - if (count != eltscnt) + if (pack != -1 ? count - 1 > eltscnt : count != eltscnt) goto cnt_mismatch; eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); for (unsigned int i = 0; i < count; i++) { + if ((unsigned) pack == i) + { + packv = make_tree_vec (eltscnt - count + 3); + for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j) + { + tree t; + TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]); + set_sb_pack_name (t, j); + maybe_push_decl (t); + TREE_TYPE (t) = eltype; + layout_decl (t, 0); + if (!processing_template_decl) + { + tree a = build1 (pack + j ? IMAGPART_EXPR : REALPART_EXPR, eltype, + unshare_expr (dexp)); + SET_DECL_VALUE_EXPR (t, a); + DECL_HAS_VALUE_EXPR_P (t) = 1; + } + } + continue; + } TREE_TYPE (v[i]) = eltype; layout_decl (v[i], 0); if (processing_template_decl) continue; tree t = unshare_expr (dexp); - t = build1 (i ? IMAGPART_EXPR : REALPART_EXPR, eltype, t); + unsigned HOST_WIDE_INT j = i; + if (pack != -1 && (unsigned) pack < i) + j = i + eltscnt - count; + t = build1 (j ? IMAGPART_EXPR : REALPART_EXPR, eltype, t); SET_DECL_VALUE_EXPR (v[i], t); DECL_HAS_VALUE_EXPR_P (v[i]) = 1; } @@ -9968,19 +10245,47 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) error_at (loc, "cannot decompose variable length vector %qT", type); goto error_out; } - if (count != eltscnt) + if (pack != -1 ? count - 1 > eltscnt : count != eltscnt) goto cnt_mismatch; eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); for (unsigned int i = 0; i < count; i++) { + if ((unsigned) pack == i) + { + packv = make_tree_vec (eltscnt - count + 3); + for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j) + { + tree t; + TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]); + set_sb_pack_name (t, j); + maybe_push_decl (t); + TREE_TYPE (t) = eltype; + layout_decl (t, 0); + if (!processing_template_decl) + { + tree a = unshare_expr (dexp); + location_t loc = DECL_SOURCE_LOCATION (t); + tree s = size_int (j + pack); + convert_vector_to_array_for_subscript (loc, &a, s); + a = build4 (ARRAY_REF, eltype, a, s, + NULL_TREE, NULL_TREE); + SET_DECL_VALUE_EXPR (t, a); + DECL_HAS_VALUE_EXPR_P (t) = 1; + } + } + continue; + } TREE_TYPE (v[i]) = eltype; layout_decl (v[i], 0); if (processing_template_decl) continue; tree t = unshare_expr (dexp); + unsigned HOST_WIDE_INT j = i; + if (pack != -1 && (unsigned) pack < i) + j = i + eltscnt - count; convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]), - &t, size_int (i)); - t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE); + &t, size_int (j)); + t = build4 (ARRAY_REF, eltype, t, size_int (j), NULL_TREE, NULL_TREE); SET_DECL_VALUE_EXPR (v[i], t); DECL_HAS_VALUE_EXPR_P (v[i]) = 1; } @@ -10004,11 +10309,11 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) goto error_out; } eltscnt = tree_to_uhwi (tsize); - if (count != eltscnt) + if (pack != -1 ? count - 1 > eltscnt : count != eltscnt) goto cnt_mismatch; - if (test_p) + if (test_p && eltscnt) return true; - if (!processing_template_decl && DECL_DECOMP_BASE (decl)) + if (!processing_template_decl && DECL_DECOMP_BASE (decl) && eltscnt) { /* For structured bindings used in conditions we need to evaluate the conversion of decl (aka e in the standard) to bool or @@ -10038,16 +10343,70 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) location_t sloc = input_location; location_t dloc = DECL_SOURCE_LOCATION (v[i]); + if ((unsigned) pack == i) + { + packv = make_tree_vec (eltscnt - count + 3); + for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j) + { + tree t; + TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]); + set_sb_pack_name (t, j); + input_location = dloc; + tree init = get_tuple_decomp_init (decl, j + pack); + tree eltype = (init == error_mark_node ? error_mark_node + : get_tuple_element_type (type, j + pack)); + input_location = sloc; + + if (VOID_TYPE_P (eltype)) + { + error ("%<std::tuple_element<%wu, %T>::type%> is " + "%<void%>", j + pack, type); + eltype = error_mark_node; + } + if (init == error_mark_node || eltype == error_mark_node) + { + inform (dloc, "in initialization of structured binding " + "pack %qD", v[pack]); + goto error_out; + } + maybe_push_decl (t); + /* Save the decltype away before reference collapse. */ + hash_map_safe_put<hm_ggc> (decomp_type_table, t, eltype); + eltype = cp_build_reference_type (eltype, !lvalue_p (init)); + TREE_TYPE (t) = eltype; + layout_decl (t, 0); + DECL_HAS_VALUE_EXPR_P (t) = 0; + if (!processing_template_decl) + { + copy_linkage (t, decl); + tree name = DECL_NAME (t); + if (TREE_STATIC (decl)) + DECL_NAME (t) = DECL_NAME (v[pack]); + cp_finish_decl (t, init, /*constexpr*/false, + /*asm*/NULL_TREE, LOOKUP_NORMAL); + if (TREE_STATIC (decl)) + { + DECL_ASSEMBLER_NAME (t); + DECL_NAME (t) = name; + } + } + } + continue; + } + + unsigned HOST_WIDE_INT j = i; + if (pack != -1 && (unsigned) pack < i) + j = i + eltscnt - count; input_location = dloc; - tree init = get_tuple_decomp_init (decl, i); + tree init = get_tuple_decomp_init (decl, j); tree eltype = (init == error_mark_node ? error_mark_node - : get_tuple_element_type (type, i)); + : get_tuple_element_type (type, j)); input_location = sloc; if (VOID_TYPE_P (eltype)) { - error ("%<std::tuple_element<%u, %T>::type%> is %<void%>", - i, type); + error ("%<std::tuple_element<%wu, %T>::type%> is %<void%>", + j, type); eltype = error_mark_node; } if (init == error_mark_node || eltype == error_mark_node) @@ -10096,11 +10455,18 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) type); else { - tree btype = find_decomp_class_base (loc, type, NULL_TREE); + tree btype = find_decomp_class_base (loc, type, NULL_TREE, + tf_warning_or_error); if (btype == error_mark_node) goto error_out; else if (btype == NULL_TREE) { + if (pack == 0 && count == 1) + { + eltscnt = 0; + packv = make_tree_vec (2); + goto done; + } error_at (loc, "cannot decompose class type %qT without non-static " "data members", type); goto error_out; @@ -10112,7 +10478,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) continue; else eltscnt++; - if (count != eltscnt) + if (pack != -1 ? count - 1 > eltscnt : count != eltscnt) goto cnt_mismatch; tree t = dexp; if (type != btype) @@ -10121,6 +10487,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) /*nonnull*/false, tf_warning_or_error); type = btype; } + unsigned HOST_WIDE_INT j = 0; unsigned int i = 0; for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) if (TREE_CODE (field) != FIELD_DECL @@ -10133,6 +10500,32 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) NULL_TREE); if (REFERENCE_REF_P (tt)) tt = TREE_OPERAND (tt, 0); + if (pack != -1 && j >= (unsigned) pack) + { + if (j == (unsigned) pack) + { + packv = make_tree_vec (eltscnt - count + 3); + i++; + } + if (j < (unsigned) pack + eltscnt - (count - 1)) + { + tree t; + TREE_VEC_ELT (packv, j + 3 - i) = t = copy_node (v[pack]); + set_sb_pack_name (t, j + 1 - i); + maybe_push_decl (t); + TREE_TYPE (t) = TREE_TYPE (tt); + layout_decl (t, 0); + if (!processing_template_decl) + { + SET_DECL_VALUE_EXPR (t, tt); + DECL_HAS_VALUE_EXPR_P (t) = 1; + } + else + DECL_HAS_VALUE_EXPR_P (t) = 0; + j++; + continue; + } + } TREE_TYPE (v[i]) = TREE_TYPE (tt); layout_decl (v[i], 0); if (!processing_template_decl) @@ -10141,7 +10534,26 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) DECL_HAS_VALUE_EXPR_P (v[i]) = 1; } i++; + j++; } + if (pack != -1 && j == (unsigned) pack) + { + gcc_checking_assert (eltscnt == count - 1); + packv = make_tree_vec (2); + } + } + done: + if (packv) + { + gcc_checking_assert (pack != -1); + TREE_VEC_ELT (packv, 0) = decl; + TREE_VEC_ELT (packv, 1) = size_int (pack); + SET_DECL_VALUE_EXPR (v[pack], packv); + DECL_HAS_VALUE_EXPR_P (v[pack]) = 1; + DECL_IGNORED_P (v[pack]) = 1; + if (!processing_template_decl) + for (unsigned int i = 0; i < TREE_VEC_LENGTH (packv) - 2U; ++i) + pushdecl (TREE_VEC_ELT (packv, 2 + i)); } if (processing_template_decl) { @@ -11226,12 +11638,12 @@ grokfndecl (tree ctype, t && t != void_list_node; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t)) { - diagnostic_t diag_kind = DK_PERMERROR; + enum diagnostics::kind diag_kind = diagnostics::kind::permerror; /* For templates, mark the default argument as erroneous and give a hard error. */ if (processing_template_decl) { - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; TREE_PURPOSE (t) = error_mark_node; } if (!has_errored) @@ -11239,7 +11651,7 @@ grokfndecl (tree ctype, has_errored = true; emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (decl), - /*diagnostic_option_id=*/0, + /*diagnostics::option_id=*/0, "friend declaration of %qD specifies default " "arguments and isn%'t a definition", decl); } @@ -11294,11 +11706,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; } @@ -12607,6 +13024,88 @@ mark_inline_variable (tree decl, location_t loc) } +/* Diagnose -Wnon-c-typedef-for-linkage pedwarn. TYPE is the unnamed class + with a typedef name for linkage purposes with freshly updated TYPE_NAME, + ORIG is the anonymous TYPE_NAME before that change. */ + +static bool +diagnose_non_c_class_typedef_for_linkage (tree type, tree orig) +{ + gcc_rich_location richloc (DECL_SOURCE_LOCATION (orig)); + tree name = DECL_NAME (TYPE_NAME (type)); + richloc.add_fixit_insert_before (IDENTIFIER_POINTER (name)); + return pedwarn (&richloc, OPT_Wnon_c_typedef_for_linkage, + "anonymous non-C-compatible type given name for linkage " + "purposes by %<typedef%> declaration"); +} + +/* Diagnose -Wnon-c-typedef-for-linkage violations on T. TYPE and ORIG + like for diagnose_non_c_class_typedef_for_linkage, T is initially equal + to TYPE but during recursion can be set to nested classes. */ + +static bool +maybe_diagnose_non_c_class_typedef_for_linkage (tree type, tree orig, tree t) +{ + if (!BINFO_BASE_BINFOS (TYPE_BINFO (t))->is_empty ()) + { + auto_diagnostic_group d; + if (diagnose_non_c_class_typedef_for_linkage (type, orig)) + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)), + "type is not C-compatible because it has a base class"); + return true; + } + for (tree field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) + switch (TREE_CODE (field)) + { + case VAR_DECL: + /* static data members have been diagnosed already. */ + continue; + case FIELD_DECL: + if (DECL_INITIAL (field)) + { + auto_diagnostic_group d; + if (diagnose_non_c_class_typedef_for_linkage (type, orig)) + inform (DECL_SOURCE_LOCATION (field), + "type is not C-compatible because %qD has default " + "member initializer", field); + return true; + } + continue; + case CONST_DECL: + continue; + case TYPE_DECL: + if (DECL_SELF_REFERENCE_P (field)) + continue; + if (DECL_IMPLICIT_TYPEDEF_P (field)) + { + if (TREE_CODE (TREE_TYPE (field)) == ENUMERAL_TYPE) + continue; + if (CLASS_TYPE_P (TREE_TYPE (field))) + { + tree tf = TREE_TYPE (field); + if (maybe_diagnose_non_c_class_typedef_for_linkage (type, orig, + tf)) + return true; + continue; + } + } + /* FALLTHRU */ + case FUNCTION_DECL: + case TEMPLATE_DECL: + { + auto_diagnostic_group d; + if (diagnose_non_c_class_typedef_for_linkage (type, orig)) + inform (DECL_SOURCE_LOCATION (field), + "type is not C-compatible because it contains %qD " + "declaration", field); + return true; + } + default: + break; + } + return false; +} + /* Assign a typedef-given name to a class or enumeration type declared as anonymous at first. This was split out of grokdeclarator because it is also used in libcc1. */ @@ -12614,7 +13113,8 @@ mark_inline_variable (tree decl, location_t loc) void name_unnamed_type (tree type, tree decl) { - gcc_assert (TYPE_UNNAMED_P (type)); + gcc_assert (TYPE_UNNAMED_P (type) + || enum_with_enumerator_for_linkage_p (type)); /* Replace the anonymous decl with the real decl. Be careful not to rename other typedefs (such as the self-reference) of type. */ @@ -12632,12 +13132,16 @@ name_unnamed_type (tree type, tree decl) /* Adjust linkage now that we aren't unnamed anymore. */ reset_type_linkage (type); + if (CLASS_TYPE_P (type) && warn_non_c_typedef_for_linkage) + maybe_diagnose_non_c_class_typedef_for_linkage (type, orig, type); + /* FIXME remangle member functions; member functions of a type with external linkage have external linkage. */ /* Check that our job is done, and that it would fail if we attempted to do it again. */ - gcc_assert (!TYPE_UNNAMED_P (type)); + gcc_assert (!TYPE_UNNAMED_P (type) + && !enum_with_enumerator_for_linkage_p (type)); } /* Check that decltype(auto) was well-formed: only plain decltype(auto) @@ -13580,9 +14084,10 @@ grokdeclarator (const cp_declarator *declarator, if (typedef_p) error_at (declspecs->locations[ds_typedef], "structured binding declaration cannot be %qs", "typedef"); - if (constexpr_p && !concept_p) - error_at (declspecs->locations[ds_constexpr], "structured " - "binding declaration cannot be %qs", "constexpr"); + if (constexpr_p && !concept_p && cxx_dialect < cxx26) + pedwarn (declspecs->locations[ds_constexpr], OPT_Wc__26_extensions, + "structured binding declaration can be %qs only with " + "%<-std=c++2c%> or %<-std=gnu++2c%>", "constexpr"); if (consteval_p) error_at (declspecs->locations[ds_consteval], "structured " "binding declaration cannot be %qs", "consteval"); @@ -13593,8 +14098,11 @@ grokdeclarator (const cp_declarator *declarator, declspecs->gnu_thread_keyword_p ? "__thread" : "thread_local"); if (concept_p) - error_at (declspecs->locations[ds_concept], - "structured binding declaration cannot be %qs", "concept"); + { + error_at (declspecs->locations[ds_concept], + "structured binding declaration cannot be %qs", "concept"); + constexpr_p = 0; + } /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ if (type_quals & TYPE_QUAL_VOLATILE) warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, @@ -13649,7 +14157,6 @@ grokdeclarator (const cp_declarator *declarator, "%<auto%> type %qT", type); inlinep = 0; typedef_p = 0; - constexpr_p = 0; consteval_p = 0; concept_p = 0; if (storage_class != sc_static) @@ -14884,7 +15391,10 @@ grokdeclarator (const cp_declarator *declarator, && unqualified_id && TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && TYPE_UNNAMED_P (type) + && (TYPE_UNNAMED_P (type) + /* An enum may have previously used an enumerator for linkage + purposes, but we want the typedef name to take priority. */ + || enum_with_enumerator_for_linkage_p (type)) && declspecs->type_definition_p && attributes_naming_typedef_ok (*attrlist) && cp_type_quals (type) == TYPE_UNQUALIFIED) @@ -17227,7 +17737,7 @@ xref_tag (enum tag_types tag_code, tree name, if (IDENTIFIER_LAMBDA_P (name)) /* Mark it as a lambda type right now. Our caller will correct the value. */ - CLASSTYPE_LAMBDA_EXPR (t) = error_mark_node; + SET_CLASSTYPE_LAMBDA_EXPR (t, error_mark_node); t = pushtag (name, t, how); } else @@ -17340,7 +17850,8 @@ xref_basetypes (tree ref, tree base_list) compatibility. */ if (processing_template_decl && CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype)) - cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN); + cxx_incomplete_type_diagnostic (NULL_TREE, basetype, + diagnostics::kind::pedwarn); if (!dependent_type_p (basetype) && !complete_type_or_else (basetype, NULL)) /* An incomplete type. Remove it from the list. */ @@ -17726,6 +18237,18 @@ start_enum (tree name, tree enumtype, tree underlying_type, return enumtype; } +/* Returns true if TYPE is an enum that uses an enumerator name for + linkage purposes. */ + +bool +enum_with_enumerator_for_linkage_p (tree type) +{ + return (cxx_dialect >= cxx20 + && UNSCOPED_ENUM_P (type) + && TYPE_ANON_P (type) + && TYPE_VALUES (type)); +} + /* After processing and defining all the values of an enumeration type, install their decls in the enumeration type. ENUMTYPE is the type object. */ @@ -17956,6 +18479,11 @@ finish_enum_value_list (tree enumtype) fixup_type_variants (current_class_type); } + /* P2115: An unnamed enum uses the name of its first enumerator for + linkage purposes; reset the type linkage if that is the case. */ + if (enum_with_enumerator_for_linkage_p (enumtype)) + reset_type_linkage (enumtype); + /* Finish debugging output for this type. */ rest_of_type_compilation (enumtype, namespace_bindings_p ()); @@ -18373,6 +18901,8 @@ build_clobber_this (clobber_kind kind) } tree exprstmt = build2 (MODIFY_EXPR, void_type_node, thisref, clobber); + if (kind == CLOBBER_OBJECT_BEGIN) + TREE_SET_CODE (exprstmt, INIT_EXPR); if (vbases) exprstmt = build_if_in_charge (exprstmt); @@ -19304,6 +19834,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; @@ -19421,14 +19964,14 @@ finish_function (bool inline_p) && !DECL_READ_P (decl) && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl) - && !warning_suppressed_p (decl,OPT_Wunused_but_set_parameter) + && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter_) && !DECL_IN_SYSTEM_HEADER (decl) && TREE_TYPE (decl) != error_mark_node && !TYPE_REF_P (TREE_TYPE (decl)) && (!CLASS_TYPE_P (TREE_TYPE (decl)) || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))) warning_at (DECL_SOURCE_LOCATION (decl), - OPT_Wunused_but_set_parameter, + OPT_Wunused_but_set_parameter_, "parameter %qD set but not used", decl); unused_but_set_errorcount = errorcount; } @@ -19957,7 +20500,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..c6c9dfc 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 @@ -6226,6 +6229,7 @@ cp_warn_deprecated_use_scopes (tree scope) bool decl_dependent_p (tree decl) { + tree orig_decl = decl; if (DECL_FUNCTION_SCOPE_P (decl) || TREE_CODE (decl) == CONST_DECL || TREE_CODE (decl) == USING_DECL @@ -6237,6 +6241,13 @@ decl_dependent_p (tree decl) if (LAMBDA_FUNCTION_P (decl) && dependent_type_p (DECL_CONTEXT (decl))) return true; + /* for-range-declaration of expansion statement as well as variable + declarations in the expansion statement body when the expansion statement + is not inside a template still need to be treated as dependent during + parsing. When the body is instantiated, in_expansion_stmt will be already + false. */ + if (VAR_P (orig_decl) && in_expansion_stmt && decl == current_function_decl) + return true; return false; } @@ -6266,6 +6277,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 +6443,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 +6474,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..8ef9f9e 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-tree.h" #include "stringpool.h" #include "tree-diagnostic.h" -#include "diagnostic-color.h" +#include "diagnostics/color.h" #include "langhooks-def.h" #include "intl.h" #include "cxx-pretty-print.h" @@ -38,8 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "cp-name-hint.h" #include "attribs.h" #include "pretty-print-format-impl.h" -#include "make-unique.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',') #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';') @@ -97,17 +96,17 @@ static void dump_scope (cxx_pretty_printer *, tree, int); static void dump_template_parms (cxx_pretty_printer *, tree, int, int); static int get_non_default_template_args_count (tree, int); static const char *function_category (tree); -static void maybe_print_constexpr_context (diagnostic_text_output_format &); -static void maybe_print_instantiation_context (diagnostic_text_output_format &); -static void print_instantiation_full_context (diagnostic_text_output_format &); -static void print_instantiation_partial_context (diagnostic_text_output_format &, +static void maybe_print_constexpr_context (diagnostics::text_sink &); +static void maybe_print_instantiation_context (diagnostics::text_sink &); +static void print_instantiation_full_context (diagnostics::text_sink &); +static void print_instantiation_partial_context (diagnostics::text_sink &, struct tinst_level *, location_t); -static void maybe_print_constraint_context (diagnostic_text_output_format &); -static void cp_diagnostic_text_starter (diagnostic_text_output_format &, - const diagnostic_info *); -static void cp_print_error_function (diagnostic_text_output_format &, - const diagnostic_info *); +static void maybe_print_constraint_context (diagnostics::text_sink &); +static void cp_diagnostic_text_starter (diagnostics::text_sink &, + const diagnostics::diagnostic_info *); +static void cp_print_error_function (diagnostics::text_sink &, + const diagnostics::diagnostic_info *); static bool cp_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, pp_token_list &); @@ -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. */ @@ -216,7 +242,7 @@ get_current_template () erroneous_templates_t *erroneous_templates; -/* Callback function diagnostic_context::m_adjust_diagnostic_info. +/* Callback function diagnostics::context::m_adjust_diagnostic_info. Errors issued when parsing a template are automatically treated like permerrors associated with the -Wtemplate-body flag and can be @@ -224,16 +250,16 @@ erroneous_templates_t *erroneous_templates; issue an error if we later need to instantiate the template. */ static void -cp_adjust_diagnostic_info (diagnostic_context *context, - diagnostic_info *diagnostic) +cp_adjust_diagnostic_info (const diagnostics::context &context, + diagnostics::diagnostic_info *diagnostic) { - if (diagnostic->kind == DK_ERROR) + if (diagnostic->m_kind == diagnostics::kind::error) if (tree tmpl = get_current_template ()) { - diagnostic->option_id = OPT_Wtemplate_body; + diagnostic->m_option_id = OPT_Wtemplate_body; - if (context->m_permissive) - diagnostic->kind = DK_WARNING; + if (context.m_permissive) + diagnostic->m_kind = diagnostics::kind::warning; bool existed; location_t &error_loc @@ -243,7 +269,7 @@ cp_adjust_diagnostic_info (diagnostic_context *context, /* Remember that this template had a parse-time error so that we'll ensure a hard error has been issued upon its instantiation. */ - error_loc = diagnostic->richloc->get_loc (); + error_loc = diagnostic->m_richloc->get_loc (); } } @@ -272,17 +298,17 @@ cp_seen_error () capacities. */ void -cxx_initialize_diagnostics (diagnostic_context *context) +cxx_initialize_diagnostics (diagnostics::context *context) { cxx_pretty_printer *pp = new cxx_pretty_printer (); - pp_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; + diagnostics::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 (); @@ -677,6 +704,20 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) } break; + case TREE_VEC: + { + /* A list of types used for a trait. */ + bool need_comma = false; + for (tree arg : tree_vec_range (t)) + { + if (need_comma) + pp_separate_with_comma (pp); + dump_type (pp, arg, flags); + need_comma = true; + } + } + break; + case TREE_LIST: /* A list of function parms. */ dump_parameters (pp, t, flags); @@ -783,6 +824,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_ws_string (pp, TYPENAME_IS_ENUM_P (t) ? "enum" : TYPENAME_IS_CLASS_P (t) ? "class" + : TYPENAME_IS_UNION_P (t) ? "union" : "typename"); dump_typename (pp, t, flags); break; @@ -1255,12 +1297,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 +3284,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. */ @@ -3673,9 +3761,9 @@ eh_spec_to_string (tree p, int /*v*/) /* Langhook for print_error_function. */ void -cxx_print_error_function (diagnostic_text_output_format &text_output, +cxx_print_error_function (diagnostics::text_sink &text_output, const char *file, - const diagnostic_info *diagnostic) + const diagnostics::diagnostic_info *diagnostic) { char *prefix; if (file) @@ -3689,8 +3777,8 @@ cxx_print_error_function (diagnostic_text_output_format &text_output, } static void -cp_diagnostic_text_starter (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic) +cp_diagnostic_text_starter (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic) { pp_set_prefix (text_output.get_printer (), text_output.build_indent_prefix (true)); @@ -3706,8 +3794,8 @@ cp_diagnostic_text_starter (diagnostic_text_output_format &text_output, /* Print current function onto BUFFER, in the process of reporting a diagnostic message. Called from cp_diagnostic_starter. */ static void -cp_print_error_function (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic) +cp_print_error_function (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic) { /* If we are in an instantiation context, current_function_decl is likely to be wrong, so just rely on print_instantiation_full_context. */ @@ -3716,7 +3804,7 @@ cp_print_error_function (diagnostic_text_output_format &text_output, /* The above is true for constraint satisfaction also. */ if (current_failed_constraint) return; - diagnostic_context *const context = &text_output.get_context (); + diagnostics::context *const context = &text_output.get_context (); if (diagnostic_last_function_changed (context, diagnostic)) { pretty_printer *const pp = text_output.get_printer (); @@ -3788,18 +3876,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 +3913,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 @@ -3854,7 +3942,7 @@ function_category (tree fn) /* Report the full context of a current template instantiation, onto BUFFER. */ static void -print_instantiation_full_context (diagnostic_text_output_format &text_output) +print_instantiation_full_context (diagnostics::text_sink &text_output) { struct tinst_level *p = current_instantiation (); location_t location = input_location; @@ -3865,14 +3953,20 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output) = ((!text_output.show_nesting_p ()) || text_output.show_locations_in_nesting_p ()); char *indent = text_output.build_indent_prefix (true); + bool expansion_stmt_p = TREE_CODE (p->tldcl) == TEMPLATE_FOR_STMT; pp_verbatim (text_output.get_printer (), - p->list_p () - ? _("%s%s%sIn substitution of %qS:\n") - : _("%s%s%sIn instantiation of %q#D:\n"), + expansion_stmt_p + ? G_("%s%s%sIn instantiation of %<template for%> " + "iteration %E:\n") + : p->list_p () + ? 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 ? ": " : "", - p->get_node ()); + expansion_stmt_p + ? TREE_VEC_ELT (p->targs, 0) + : p->get_node ()); free (indent); location = p->locus; p = p->next; @@ -3882,21 +3976,21 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output) } static void -print_location (diagnostic_text_output_format &text_output, +print_location (diagnostics::text_sink &text_output, location_t loc) { expanded_location xloc = expand_location (loc); 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); } /* A RAII class for use when emitting a line of contextual information - via pp_verbatim to a diagnostic_text_output_format to add before/after + via pp_verbatim to a diagnostics::text_sink to add before/after behaviors to the pp_verbatim calls. If the text output has show_nesting_p (), then the ctor prints @@ -3911,7 +4005,7 @@ print_location (diagnostic_text_output_format &text_output, class auto_context_line { public: - auto_context_line (diagnostic_text_output_format &text_output, + auto_context_line (diagnostics::text_sink &text_output, location_t loc, bool show_locus = false) : m_text_output (text_output), @@ -3942,7 +4036,7 @@ public: diagnostic_show_locus (&m_text_output.get_context (), m_text_output.get_source_printing_options (), &rich_loc, - DK_NOTE, pp); + diagnostics::kind::note, pp); pp_set_prefix (pp, saved_prefix); } } @@ -3954,12 +4048,12 @@ public: diagnostic_show_locus (&m_text_output.get_context (), m_text_output.get_source_printing_options (), &rich_loc, - DK_NOTE, pp); + diagnostics::kind::note, pp); pp_set_prefix (pp, saved_prefix); } } private: - diagnostic_text_output_format &m_text_output; + diagnostics::text_sink &m_text_output; location_t m_loc; bool m_show_locus; }; @@ -3968,7 +4062,7 @@ private: prints a single line of instantiation context. */ static void -print_instantiation_partial_context_line (diagnostic_text_output_format &text_output, +print_instantiation_partial_context_line (diagnostics::text_sink &text_output, struct tinst_level *t, location_t loc, bool recursive_p) { @@ -3981,32 +4075,39 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou if (t != NULL) { - if (t->list_p ()) + if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT) + pp_verbatim (pp, + recursive_p + ? G_("recursively required from %<template for%> " + "iteration %E\n") + : G_("required from %<template for%> iteration %E\n"), + TREE_VEC_ELT (t->targs, 0)); + else 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")); } } /* Same as print_instantiation_full_context but less verbose. */ static void -print_instantiation_partial_context (diagnostic_text_output_format &text_output, +print_instantiation_partial_context (diagnostics::text_sink &text_output, struct tinst_level *t0, location_t loc) { struct tinst_level *t; @@ -4049,8 +4150,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; @@ -4077,7 +4178,7 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output, /* Called from cp_thing to print the template context for an error. */ static void -maybe_print_instantiation_context (diagnostic_text_output_format &text_output) +maybe_print_instantiation_context (diagnostics::text_sink &text_output) { if (!problematic_instantiation_changed () || current_instantiation () == 0) return; @@ -4089,7 +4190,7 @@ maybe_print_instantiation_context (diagnostic_text_output_format &text_output) /* Report what constexpr call(s) we're trying to expand, if any. */ void -maybe_print_constexpr_context (diagnostic_text_output_format &text_output) +maybe_print_constexpr_context (diagnostics::text_sink &text_output) { vec<tree> call_stack = cx_error_context (); unsigned ix; @@ -4101,7 +4202,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); } @@ -4109,16 +4210,16 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output) static void -print_constrained_decl_info (diagnostic_text_output_format &text_output, +print_constrained_decl_info (diagnostics::text_sink &text_output, tree decl) { auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl)); 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 -print_concept_check_info (diagnostic_text_output_format &text_output, +print_concept_check_info (diagnostics::text_sink &text_output, tree expr, tree map, tree args) { gcc_assert (concept_check_p (expr)); @@ -4129,7 +4230,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); @@ -4143,7 +4244,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output, context, if any. */ static tree -print_constraint_context_head (diagnostic_text_output_format &text_output, +print_constraint_context_head (diagnostics::text_sink &text_output, tree cxt, tree args) { tree src = TREE_VALUE (cxt); @@ -4151,7 +4252,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)) @@ -4167,7 +4268,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output, } static void -print_requires_expression_info (diagnostic_text_output_format &text_output, +print_requires_expression_info (diagnostics::text_sink &text_output, tree constr, tree args) { @@ -4180,11 +4281,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); @@ -4198,7 +4298,7 @@ print_requires_expression_info (diagnostic_text_output_format &text_output, } void -maybe_print_single_constraint_context (diagnostic_text_output_format &text_output, +maybe_print_single_constraint_context (diagnostics::text_sink &text_output, tree failed) { if (!failed) @@ -4229,7 +4329,7 @@ maybe_print_single_constraint_context (diagnostic_text_output_format &text_outpu } void -maybe_print_constraint_context (diagnostic_text_output_format &text_output) +maybe_print_constraint_context (diagnostics::text_sink &text_output) { if (!current_failed_constraint) return; @@ -4842,18 +4942,20 @@ maybe_warn_variadic_templates (void) C++0x. */ bool pedwarn_cxx98 (location_t location, - diagnostic_option_id option_id, + diagnostics::option_id option_id, const char *gmsgid, ...) { - diagnostic_info diagnostic; + diagnostics::diagnostic_info diagnostic; va_list ap; bool ret; rich_location richloc (line_table, location); va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, - (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING); - diagnostic.option_id = option_id; + (cxx_dialect == cxx98 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning)); + diagnostic.m_option_id = option_id; ret = diagnostic_report_diagnostic (global_dc, &diagnostic); va_end (ap); return ret; diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc index a9d8e2f..204769f 100644 --- a/gcc/cp/except.cc +++ b/gcc/cp/except.cc @@ -367,6 +367,8 @@ initialize_handler_parm (tree decl, tree exp) MUST_NOT_THROW_EXPR. */ init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); init = build_must_not_throw_expr (init, NULL_TREE); + if (init && TREE_CODE (init) == MUST_NOT_THROW_EXPR) + MUST_NOT_THROW_CATCH_P (init) = 1; } decl = pushdecl (decl); @@ -523,6 +525,7 @@ begin_eh_spec_block (void) r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (r) = 1; + MUST_NOT_THROW_NOEXCEPT_P (r) = 1; } else r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE); @@ -614,6 +617,7 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/) { cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup, NULL_TREE); + MUST_NOT_THROW_THROW_P (cleanup) = 1; TARGET_EXPR_CLEANUP (exp) = cleanup; } @@ -712,6 +716,11 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain) allocate_expr = do_allocate_exception (temp_type); if (allocate_expr == error_mark_node) return error_mark_node; + /* Copy ptr inside of the CLEANUP_POINT_EXPR + added below to a TARGET_EXPR slot added outside of it, + otherwise during constant evaluation of throw expression + we'd diagnose accessing ptr outside of its lifetime. */ + tree ptr_copy = get_internal_target_expr (null_pointer_node); allocate_expr = get_internal_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); @@ -763,10 +772,17 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain) /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); + exp = build2 (COMPOUND_EXPR, void_type_node, exp, + build2 (MODIFY_EXPR, void_type_node, + TARGET_EXPR_SLOT (ptr_copy), ptr)); + ptr = TARGET_EXPR_SLOT (ptr_copy); + /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); + exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), ptr_copy, exp); + throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; @@ -1202,6 +1218,20 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain) return true; } +/* If EXPR is not noexcept, explain why. */ + +void +explain_not_noexcept (tree expr) +{ + tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); + if (!fn) + /* The call was noexcept, nothing to do. */; + else if (DECL_P (fn)) + inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn); + else + inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn)); +} + /* Return true iff SPEC is throw() or noexcept(true). */ bool diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc index 2157cfb..32dc3ee 100644 --- a/gcc/cp/expr.cc +++ b/gcc/cp/expr.cc @@ -102,6 +102,9 @@ mark_use (tree expr, bool rvalue_p, bool read_p, if (reject_builtin && reject_gcc_builtin (expr, loc)) return error_mark_node; + if (TREE_TYPE (expr) && VOID_TYPE_P (TREE_TYPE (expr))) + read_p = false; + if (read_p) mark_exp_read (expr); @@ -211,7 +214,7 @@ mark_use (tree expr, bool rvalue_p, bool read_p, } return expr; } - gcc_fallthrough(); + gcc_fallthrough (); CASE_CONVERT: recurse_op[0] = true; break; @@ -352,6 +355,9 @@ mark_exp_read (tree exp) if (exp == NULL) return; + if (TREE_TYPE (exp) && VOID_TYPE_P (TREE_TYPE (exp))) + return; + switch (TREE_CODE (exp)) { case VAR_DECL: @@ -361,16 +367,20 @@ mark_exp_read (tree exp) case PARM_DECL: DECL_READ_P (exp) = 1; break; + CASE_CONVERT: case ARRAY_REF: case COMPONENT_REF: case MODIFY_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: - CASE_CONVERT: case ADDR_EXPR: case INDIRECT_REF: case FLOAT_EXPR: case VIEW_CONVERT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: mark_exp_read (TREE_OPERAND (exp, 0)); break; case COMPOUND_EXPR: diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index e589e45..f19794c 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. */ @@ -3549,9 +3557,19 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, alloc_expr = maybe_wrap_new_for_constexpr (alloc_expr, type, cookie_size); + bool std_placement = std_placement_new_fn_p (alloc_fn); + + /* For std placement new, clobber the object if the constructor won't do it + in start_preparsed_function. This is most important for activating an + array in a union (c++/121068), but should also help the optimizers. */ + const bool do_clobber + = (std_placement && !*init && flag_lifetime_dse > 1 + && (!CLASS_TYPE_P (elt_type) + || type_has_non_user_provided_default_constructor (elt_type))); + /* In the simple case, we can stop now. */ pointer_type = build_pointer_type (type); - if (!cookie_size && !is_initialized && !member_delete_p) + if (!cookie_size && !is_initialized && !member_delete_p && !do_clobber) return build_nop (pointer_type, alloc_expr); /* Store the result of the allocation call in a variable so that we can @@ -3585,8 +3603,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, So check for a null exception spec on the op new we just called. */ nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn)); - check_new - = flag_check_new || (nothrow && !std_placement_new_fn_p (alloc_fn)); + check_new = flag_check_new || (nothrow && !std_placement); if (cookie_size) { @@ -3641,6 +3658,29 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* Any further uses of alloc_node will want this type, too. */ alloc_node = fold_convert (non_const_pointer_type, alloc_node); + tree clobber_expr = NULL_TREE; + if (do_clobber) + { + tree clobber = build_clobber (elt_type, CLOBBER_OBJECT_BEGIN); + CONSTRUCTOR_IS_DIRECT_INIT (clobber) = true; + if (array_p) + { + /* Clobber each element rather than the array at once. */ + tree maxindex = cp_build_binary_op (input_location, + MINUS_EXPR, outer_nelts, + integer_one_node, + complain); + clobber_expr = build_vec_init (data_addr, maxindex, clobber, + /*valinit*/false, /*from_arr*/0, + complain, nullptr); + } + else + { + tree targ = cp_build_fold_indirect_ref (data_addr); + clobber_expr = cp_build_init_expr (targ, clobber); + } + } + /* Now initialize the allocated object. Note that we preevaluate the initialization expression, apart from the actual constructor call or assignment--we do this because we want to delay the allocation as long @@ -3869,6 +3909,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, if (init_expr) rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval); + if (clobber_expr) + rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), clobber_expr, rval); if (cookie_expr) rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval); @@ -4173,7 +4215,8 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type, "possible problem detected in invocation of " "operator %<delete []%>")) { - cxx_incomplete_type_diagnostic (base, type, DK_WARNING); + cxx_incomplete_type_diagnostic (base, type, + diagnostics::kind::warning); inform (loc, "neither the destructor nor the " "class-specific operator %<delete []%> will be called, " "even if they are declared when the class is defined"); @@ -4708,6 +4751,9 @@ build_vec_init (tree base, tree maxindex, tree init, the partially constructed array if an exception is thrown. But don't do this if we're assigning. */ if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + /* And don't clean up from clobbers, the actual initialization will + follow as a separate build_vec_init. */ + && !(init && TREE_CLOBBER_P (init)) && from_array != 2) { tree e; @@ -4747,7 +4793,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? */ @@ -5277,7 +5324,8 @@ build_delete (location_t loc, tree otype, tree addr, "possible problem detected in invocation of " "%<operator delete%>")) { - cxx_incomplete_type_diagnostic (addr, type, DK_WARNING); + cxx_incomplete_type_diagnostic (addr, type, + diagnostics::kind::warning); inform (loc, "neither the destructor nor the class-specific " "%<operator delete%> will be called, even if " diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index f0a54b6..711e3b7 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -150,7 +150,7 @@ begin_lambda_type (tree lambda) /* Cross-reference the expression and the type. */ LAMBDA_EXPR_CLOSURE (lambda) = type; - CLASSTYPE_LAMBDA_EXPR (type) = lambda; + SET_CLASSTYPE_LAMBDA_EXPR (type, lambda); /* In C++17, assume the closure is literal; we'll clear the flag later if necessary. */ @@ -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); } @@ -407,10 +409,11 @@ lambda_proxy_type (tree ref) /* MEMBER is a capture field in a lambda closure class. Now that we're inside the operator(), build a placeholder var for future lookups and - debugging. */ + debugging. But if EARLY_P is true, we do not have the real operator() + yet and we have to proceed differently. */ -static tree -build_capture_proxy (tree member, tree init) +tree +build_capture_proxy (tree member, tree init, bool early_p) { tree var, object, fn, closure, name, lam, type; @@ -436,13 +439,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)) @@ -493,11 +504,19 @@ build_capture_proxy (tree member, tree init) if (name == this_identifier) { + if (early_p) + return var; gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member); LAMBDA_EXPR_THIS_CAPTURE (lam) = var; } - if (fn == current_function_decl) + if (early_p) + { + gcc_checking_assert (current_binding_level->kind == sk_lambda); + /* insert_capture_proxy below wouldn't push into the lambda scope. */ + pushdecl (var); + } + else if (fn == current_function_decl) insert_capture_proxy (var); else vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var); @@ -717,7 +736,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, = tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda)); if (LAMBDA_EXPR_CLOSURE (lambda)) - return build_capture_proxy (member, initializer); + return build_capture_proxy (member, initializer, /*early_p=*/false); /* For explicit captures we haven't started the function yet, so we wait and build the proxy from cp_parser_lambda_body. */ LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (lambda)) = true; @@ -813,6 +832,14 @@ lambda_expr_this_capture (tree lambda, int add_capture_p) if (cp_unevaluated_operand) add_capture_p = false; + /* If we captured 'this' but don't have a capture proxy yet, look up the + captured 'this' again. */ + if (this_capture && TREE_CODE (this_capture) == FIELD_DECL) + { + gcc_assert (!add_capture_p); + this_capture = NULL_TREE; + } + /* Try to default capture 'this' if we can. */ if (!this_capture) { @@ -917,8 +944,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; @@ -929,6 +957,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p) result = rvalue (result); } + gcc_checking_assert (!result || result == error_mark_node + || TYPE_PTR_P (TREE_TYPE (result))); + return result; } @@ -958,10 +989,14 @@ resolvable_dummy_lambda (tree object) tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object)); gcc_assert (!TYPE_PTR_P (type)); + tree fn; if (type != current_class_type && current_class_type && LAMBDA_TYPE_P (current_class_type) - && lambda_function (current_class_type) + && (fn = lambda_function (current_class_type)) + /* Even dummy lambdas have an operator() since P2036, but the + dummy operator() doesn't have this set. */ + && DECL_LAMBDA_FUNCTION_P (fn) && DERIVED_FROM_P (type, nonlambda_method_basetype())) return CLASSTYPE_LAMBDA_EXPR (current_class_type); @@ -1016,13 +1051,19 @@ maybe_generic_this_capture (tree object, tree fns) } } -/* Returns the innermost non-lambda function. */ +/* Returns the innermost non-lambda function. If ONLY_SKIP_CONSTEVAL_BLOCK_P, + we only skip lambda functions that represent consteval blocks. */ tree -current_nonlambda_function (void) +current_nonlambda_function (bool only_skip_consteval_block_p/*=false*/) { tree fn = current_function_decl; - while (fn && LAMBDA_FUNCTION_P (fn)) + tree lam; + while (fn && LAMBDA_FUNCTION_P (fn) + && (!only_skip_consteval_block_p + /* Only keep going if FN represents a consteval block. */ + || ((lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fn))) + && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam)))) fn = decl_function_context (fn); return fn; } @@ -1033,12 +1074,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 +1088,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)) @@ -1124,7 +1162,9 @@ maybe_add_lambda_conv_op (tree type) tree lam = CLASSTYPE_LAMBDA_EXPR (type); if (LAMBDA_EXPR_CAPTURE_LIST (lam) != NULL_TREE - || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE) + || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE + /* CWG2561 ...and no explicit object parameter. */ + || DECL_XOBJ_MEMBER_FUNCTION_P (callop)) return; if (processing_template_decl) @@ -1757,6 +1797,17 @@ record_lambda_scope_sig_discriminator (tree lambda, tree fn) LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda) = sig->count++; } +/* Push the proxies for any explicit captures in LAMBDA_EXPR. + If EARLY_P, we do not have the real operator() yet. */ + +void +push_capture_proxies (tree lambda_expr, bool early_p) +{ + for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap; + cap = TREE_CHAIN (cap)) + build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap), early_p); +} + tree start_lambda_function (tree fco, tree lambda_expr) { @@ -1769,9 +1820,7 @@ start_lambda_function (tree fco, tree lambda_expr) tree body = begin_function_body (); /* Push the proxies for any explicit captures. */ - for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap; - cap = TREE_CHAIN (cap)) - build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap)); + push_capture_proxies (lambda_expr); return body; } @@ -1858,6 +1907,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 +1920,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 +1946,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); } } @@ -1898,7 +1980,7 @@ finish_lambda_function (tree body) { finish_function_body (body); - prune_lambda_captures (body); + prune_lambda_captures (cur_stmt_list); /* Finish the function and generate code for it if necessary. */ tree fn = finish_function (/*inline_p=*/true); diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index c12b084..da86989 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -172,7 +172,7 @@ init_operators (void) /* This loop iterates backwards because we need to move the assignment operators down to their correct slots. I.e. morally equivalent to an overlapping memmove where dest > src. Slot - zero is for error_mark, so hae no operator. */ + zero is for error_mark, so has no operator. */ for (unsigned ix = OVL_OP_MAX; --ix;) { ovl_op_info_t *op_ptr = &ovl_op_info[false][ix]; @@ -368,6 +368,61 @@ cxx_init (void) cxx_init_decl_processing (); + if (warn_keyword_macro) + { + for (unsigned int i = 0; i < num_c_common_reswords; ++i) + /* For C++ none of the keywords in [lex.key] starts with underscore, + don't register anything like that. Don't complain about + ObjC or Transactional Memory keywords. */ + if (c_common_reswords[i].word[0] == '_') + continue; + else if (c_common_reswords[i].disable & (D_TRANSMEM | D_OBJC)) + continue; + else + { + tree id = get_identifier (c_common_reswords[i].word); + if (IDENTIFIER_KEYWORD_P (id) + /* Don't register keywords with spaces. */ + && IDENTIFIER_POINTER (id)[IDENTIFIER_LENGTH (id) - 1] != ' ') + cpp_warn (parse_in, IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id)); + } + if (cxx_dialect >= cxx11) + { + cpp_warn (parse_in, "final"); + cpp_warn (parse_in, "override"); + cpp_warn (parse_in, "noreturn"); + if (cxx_dialect < cxx26) + cpp_warn (parse_in, "carries_dependency"); + } + if (cxx_dialect >= cxx14) + cpp_warn (parse_in, "deprecated"); + if (cxx_dialect >= cxx17) + { + cpp_warn (parse_in, "fallthrough"); + cpp_warn (parse_in, "maybe_unused"); + cpp_warn (parse_in, "nodiscard"); + } + if (cxx_dialect >= cxx20) + { + cpp_warn (parse_in, "likely"); + cpp_warn (parse_in, "unlikely"); + cpp_warn (parse_in, "no_unique_address"); + } + if (flag_modules) + { + cpp_warn (parse_in, "import"); + cpp_warn (parse_in, "module"); + } + if (cxx_dialect >= cxx23) + cpp_warn (parse_in, "assume"); + if (cxx_dialect >= cxx26) + { + cpp_warn (parse_in, "replaceable_if_eligible"); + cpp_warn (parse_in, "trivially_relocatable_if_eligible"); + } + } + if (c_common_init () == false) { input_location = saved_loc; @@ -749,6 +804,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 +1137,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 +1171,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 +1193,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..f48cb22 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -203,6 +203,7 @@ static void write_conversion_operator_name (const tree); static void write_source_name (tree); static void write_literal_operator_name (tree); static void write_unnamed_type_name (const tree); +static void write_unnamed_enum_name (const tree); static void write_closure_type_name (const tree); static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *, const unsigned int); @@ -1048,6 +1049,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. */ @@ -1585,7 +1592,9 @@ write_unqualified_name (tree decl) tree type = TREE_TYPE (decl); if (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (type)) + && enum_with_enumerator_for_linkage_p (type)) + write_unnamed_enum_name (type); + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type)) write_unnamed_type_name (type); else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) write_closure_type_name (type); @@ -1814,6 +1823,17 @@ write_unnamed_type_name (const tree type) write_compact_number (discriminator); } +/* <unnamed-enum-name> ::= Ue <underlying type> <enumerator source-name> */ + +static void +write_unnamed_enum_name (const tree type) +{ + MANGLE_TRACE_TREE ("unnamed-enum-name", type); + write_string ("Ue"); + write_type (ENUM_UNDERLYING_TYPE (type)); + write_source_name (DECL_NAME (TREE_VALUE (TYPE_VALUES (type)))); +} + /* ABI issue #47: if a function template parameter is not "natural" for its argument we must mangle the parameter. */ @@ -3739,11 +3759,59 @@ write_expression (tree expr) || !zero_init_expr_p (ce->value)) last_nonzero = i; + tree prev_field = NULL_TREE; if (undigested || last_nonzero != UINT_MAX) for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) { if (i > last_nonzero) break; + if (!undigested && !CONSTRUCTOR_NO_CLEARING (expr) + && (TREE_CODE (etype) == RECORD_TYPE + || TREE_CODE (etype) == ARRAY_TYPE)) + { + /* Write out any implicit non-trailing zeros + (which we neglected to do before v21). */ + if (TREE_CODE (etype) == RECORD_TYPE) + { + tree field; + if (i == 0) + field = first_field (etype); + else + field = DECL_CHAIN (prev_field); + for (;;) + { + field = next_subobject_field (field); + if (field == ce->index) + break; + if (abi_check (21)) + write_expression (build_zero_cst + (TREE_TYPE (field))); + field = DECL_CHAIN (field); + } + } + else if (TREE_CODE (etype) == ARRAY_TYPE) + { + unsigned HOST_WIDE_INT j; + if (i == 0) + j = 0; + else + j = 1 + tree_to_uhwi (prev_field); + unsigned HOST_WIDE_INT k; + if (TREE_CODE (ce->index) == RANGE_EXPR) + k = tree_to_uhwi (TREE_OPERAND (ce->index, 0)); + else + k = tree_to_uhwi (ce->index); + tree zero = NULL_TREE; + for (; j < k; ++j) + if (abi_check (21)) + { + if (!zero) + zero = build_zero_cst (TREE_TYPE (etype)); + write_expression (zero); + } + } + } + if (!undigested && TREE_CODE (etype) == UNION_TYPE) { /* Express the active member as a designator. */ @@ -3788,6 +3856,9 @@ write_expression (tree expr) else for (unsigned j = 0; j < reps; ++j) write_expression (ce->value); + prev_field = ce->index; + if (prev_field && TREE_CODE (prev_field) == RANGE_EXPR) + prev_field = TREE_OPERAND (prev_field, 1); } } else @@ -4446,23 +4517,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 +4537,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/mapper-client.cc b/gcc/cp/mapper-client.cc index 9477fee..ac414f0 100644 --- a/gcc/cp/mapper-client.cc +++ b/gcc/cp/mapper-client.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_VECTOR #define INCLUDE_MAP #include "system.h" +#include "libiberty.h" #include "line-map.h" #include "rich-location.h" @@ -51,37 +52,18 @@ static module_client * spawn_mapper_program (char const **errmsg, std::string &name, char const *full_program_name) { - /* Split writable at white-space. No space-containing args for - you! */ - // At most every other char could be an argument - char **argv = new char *[name.size () / 2 + 2]; - unsigned arg_no = 0; - char *str = new char[name.size ()]; - memcpy (str, name.c_str () + 1, name.size ()); - - for (auto ptr = str; ; ++ptr) - { - while (*ptr == ' ') - ptr++; - if (!*ptr) - break; - - if (!arg_no) - { - /* @name means look in the compiler's install dir. */ - if (ptr[0] == '@') - ptr++; - else - full_program_name = nullptr; - } - - argv[arg_no++] = ptr; - while (*ptr && *ptr != ' ') - ptr++; - if (!*ptr) - break; - *ptr = 0; - } + // Split mapper argument into parameters. + char** original_argv = buildargv (name.c_str () + 1); + int arg_no = countargv (original_argv); + char **argv = new char *[arg_no + 1]; + for (int i = 0; i < arg_no; i++) + argv[i] = original_argv[i]; + + /* @name means look in the compiler's install dir. */ + if (arg_no && argv[0][0] == '@') + argv[0] = argv[0] + 1; + else + full_program_name = nullptr; argv[arg_no] = nullptr; auto *pex = pex_init (PEX_USE_PIPES, progname, NULL); @@ -108,8 +90,8 @@ spawn_mapper_program (char const **errmsg, std::string &name, int err; *errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err); } - delete[] str; delete[] argv; + freeargv (original_argv); int fd_from = -1, fd_to = -1; if (!*errmsg) diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 05c19cf..ef8370f 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1187,15 +1187,15 @@ early_check_defaulted_comparison (tree fn) if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR) && !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node)) { - diagnostic_t kind = DK_UNSPECIFIED; + enum diagnostics::kind kind = diagnostics::kind::unspecified; int opt = 0; if (is_auto (TREE_TYPE (fn))) - kind = DK_PEDWARN; + kind = diagnostics::kind::pedwarn; else - kind = DK_ERROR; + kind = diagnostics::kind::error; emit_diagnostic (kind, loc, opt, "defaulted %qD must return %<bool%>", fn); - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) ok = false; } @@ -1851,6 +1851,9 @@ synthesize_method (tree fndecl) finish_function_body (stmt); finish_function (/*inline_p=*/false); + /* Remember that we were defined in this module. */ + set_instantiating_module (fndecl); + if (!DECL_DELETED_FN (fndecl)) expand_or_defer_fn (fndecl); @@ -1928,8 +1931,8 @@ is_stub_object (tree expr) /* Build a std::declval<TYPE>() expression and return it. */ -tree -build_trait_object (tree type) +static tree +build_trait_object (tree type, tsubst_flags_t complain) { /* TYPE can't be a function with cv-/ref-qualifiers: std::declval is defined as @@ -1942,13 +1945,18 @@ build_trait_object (tree type) if (FUNC_OR_METHOD_TYPE_P (type) && (type_memfn_quals (type) != TYPE_UNQUALIFIED || type_memfn_rqual (type) != REF_QUAL_NONE)) - return error_mark_node; + { + if (complain & tf_error) + error ("object cannot have qualified function type %qT", type); + return error_mark_node; + } return build_stub_object (type); } /* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...). If the - given is not invocable, returns error_mark_node. */ + given is not invocable, returns error_mark_node, unless COMPLAIN includes + tf_error. */ tree build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) @@ -2036,22 +2044,26 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) const_tree name = DECL_NAME (datum_decl); if (name && (id_equal (name, "reference_wrapper"))) { - /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>, + /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>, i.e., decltype(datum.get()). */ datum_type = TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0); + datum_type = cp_build_reference_type (datum_type, false); datum_is_refwrap = true; } } } - tree datum_expr = build_trait_object (datum_type); + tree datum_expr = build_trait_object (datum_type, complain); if (!ptrmem_is_same_or_base_of_datum && !datum_is_refwrap) /* 1.3 & 1.6: Try to dereference datum_expr. */ datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr, RO_UNARY_STAR, NULL_TREE, complain); - tree fn_expr = build_trait_object (fn_type); + if (error_operand_p (datum_expr)) + return error_mark_node; + + tree fn_expr = build_trait_object (fn_type, complain); ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain); if (error_operand_p (ptrmem_expr)) @@ -2068,7 +2080,9 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i) { tree arg_type = TREE_VEC_ELT (arg_types, i); - tree arg = build_trait_object (arg_type); + tree arg = build_trait_object (arg_type, complain); + if (error_operand_p (arg)) + return error_mark_node; vec_safe_push (args, arg); } @@ -2077,8 +2091,8 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) invoke_expr = build_offset_ref_call_from_tree (ptrmem_expr, &args, complain); else /* 1.7. */ - invoke_expr = finish_call_expr (build_trait_object (fn_type), &args, false, - false, complain); + invoke_expr = finish_call_expr (build_trait_object (fn_type, complain), + &args, false, false, complain); return invoke_expr; } @@ -2227,12 +2241,20 @@ check_nontriv (tree *tp, int *, void *) /* Return declval<T>() = declval<U>() treated as an unevaluated operand. */ static tree -assignable_expr (tree to, tree from) +assignable_expr (tree to, tree from, bool explain) { cp_unevaluated cp_uneval_guard; - to = build_trait_object (to); - from = build_trait_object (from); - tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none); + tsubst_flags_t complain = explain ? tf_error : tf_none; + + to = build_trait_object (to, complain); + if (to == error_mark_node) + return error_mark_node; + + from = build_trait_object (from, complain); + if (from == error_mark_node) + return error_mark_node; + + tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, complain); return r; } @@ -2244,27 +2266,30 @@ assignable_expr (tree to, tree from) Return something equivalent in well-formedness and triviality. */ static tree -constructible_expr (tree to, tree from) +constructible_expr (tree to, tree from, bool explain) { tree expr; cp_unevaluated cp_uneval_guard; + tsubst_flags_t complain = explain ? tf_error : tf_none; const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { + if (ABSTRACT_CLASS_TYPE_P (to)) + return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; if (!TYPE_REF_P (to)) to = cp_build_reference_type (to, /*rval*/false); tree ob = build_stub_object (to); if (len == 0) - expr = build_value_init (ctype, tf_none); + expr = build_value_init (ctype, complain); else { vec_alloc (args, len); for (tree arg : tree_vec_range (from)) args->quick_push (build_stub_object (arg)); expr = build_special_member_call (ob, complete_ctor_identifier, &args, - ctype, LOOKUP_NORMAL, tf_none); + ctype, LOOKUP_NORMAL, complain); } if (expr == error_mark_node) return error_mark_node; @@ -2274,7 +2299,7 @@ constructible_expr (tree to, tree from) { tree dtor = build_special_member_call (ob, complete_dtor_identifier, NULL, ctype, LOOKUP_NORMAL, - tf_none); + complain); if (dtor == error_mark_node) return error_mark_node; if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) @@ -2284,12 +2309,15 @@ constructible_expr (tree to, tree from) else { if (len == 0) - return build_value_init (strip_array_types (to), tf_none); + return build_value_init (strip_array_types (to), complain); if (len > 1) { if (cxx_dialect < cxx20) - /* Too many initializers. */ - return error_mark_node; + { + if (explain) + error ("too many initializers for non-class type %qT", to); + return error_mark_node; + } /* In C++20 this is well-formed: using T = int[2]; @@ -2310,9 +2338,11 @@ constructible_expr (tree to, tree from) } else from = build_stub_object (TREE_VEC_ELT (from, 0)); + + tree orig_from = from; expr = perform_direct_initialization_if_possible (to, from, /*cast*/false, - tf_none); + complain); /* If t(e) didn't work, maybe t{e} will. */ if (expr == NULL_TREE && len == 1 @@ -2324,76 +2354,156 @@ constructible_expr (tree to, tree from) CONSTRUCTOR_IS_PAREN_INIT (from) = true; expr = perform_direct_initialization_if_possible (to, from, /*cast*/false, - tf_none); + complain); + } + + if (expr == NULL_TREE && explain) + { + if (len > 1) + error ("too many initializers for non-class type %qT", to); + else + { + /* Redo the implicit conversion for diagnostics. */ + int count = errorcount + warningcount; + perform_implicit_conversion_flags (to, orig_from, complain, + LOOKUP_NORMAL); + if (count == errorcount + warningcount) + /* The message may have been suppressed due to -w + -fpermissive, + emit a generic response instead. */ + error ("the conversion is invalid"); + } } } return expr; } +/* 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, bool explain) +{ + cp_unevaluated cp_uneval_guard; + tsubst_flags_t complain = explain ? tf_error : tf_none; + int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR; + if (TYPE_REF_P (to)) + return void_node; + if (!COMPLETE_TYPE_P (complete_type (to))) + { + if (explain) + error_at (location_of (to), "%qT is incomplete", to); + return error_mark_node; + } + to = strip_array_types (to); + if (CLASS_TYPE_P (to)) + { + to = build_trait_object (to, complain); + return build_delete (input_location, TREE_TYPE (to), to, + sfk_complete_destructor, flags, 0, complain); + } + /* [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. */ + assignment or a list of types for construction. If EXPLAIN is + set, emit a diagnostic explaining why the operation failed. */ static tree -is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) +is_xible_helper (enum tree_code code, tree to, tree from, bool explain) { to = complete_type (to); deferring_access_check_sentinel acs (dk_no_deferred); - if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to) - || (from && FUNC_OR_METHOD_TYPE_P (from) - && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))) - return error_mark_node; + + if (VOID_TYPE_P (to)) + { + if (explain) + error_at (location_of (to), "%qT is incomplete", to); + return error_mark_node; + } + if (from + && FUNC_OR_METHOD_TYPE_P (from) + && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))) + { + if (explain) + error ("%qT is a qualified function type", from); + return error_mark_node; + } + tree expr; if (code == MODIFY_EXPR) - expr = assignable_expr (to, from); - else if (trivial && TREE_VEC_LENGTH (from) > 1 - && cxx_dialect < cxx20) - return error_mark_node; // only 0- and 1-argument ctors can be trivial - // before C++20 aggregate paren init + expr = assignable_expr (to, from, explain); + else if (code == BIT_NOT_EXPR) + expr = destructible_expr (to, explain); else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to)) - return error_mark_node; // can't construct an array of unknown bound + { + if (explain) + error ("cannot construct an array of unknown bound"); + return error_mark_node; + } else - expr = constructible_expr (to, from); + expr = constructible_expr (to, from, explain); return expr; } /* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_trivially_xible (enum tree_code code, tree to, tree from) +is_trivially_xible (enum tree_code code, tree to, tree from, + bool explain/*=false*/) { - tree expr = is_xible_helper (code, to, from, /*trivial*/true); + tree expr = is_xible_helper (code, to, from, explain); if (expr == NULL_TREE || expr == error_mark_node) return false; + tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL); + if (explain && nt) + inform (location_of (nt), "%qE is non-trivial", nt); return !nt; } /* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_nothrow_xible (enum tree_code code, tree to, tree from) +is_nothrow_xible (enum tree_code code, tree to, tree from, + bool explain/*=false*/) { ++cp_noexcept_operand; - tree expr = is_xible_helper (code, to, from, /*trivial*/false); + tree expr = is_xible_helper (code, to, from, explain); --cp_noexcept_operand; if (expr == NULL_TREE || expr == error_mark_node) return false; - return expr_noexcept_p (expr, tf_none); + + bool is_noexcept = expr_noexcept_p (expr, tf_none); + if (explain && !is_noexcept) + explain_not_noexcept (expr); + return is_noexcept; } /* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or constructible (otherwise) from FROM, which is a single type for - assignment or a list of types for construction. */ + assignment or a list of types for construction. If EXPLAIN, diagnose + why we returned false. */ bool -is_xible (enum tree_code code, tree to, tree from) +is_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/) { - tree expr = is_xible_helper (code, to, from, /*trivial*/false); + tree expr = is_xible_helper (code, to, from, explain); if (expr == error_mark_node) return false; return !!expr; @@ -2418,7 +2528,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) return false; /* We don't check is_constructible<T, U>: if T isn't constructible from U, we won't be able to create a conversion. */ - tree val = build_trait_object (from); + tree val = build_trait_object (from, tf_none); if (val == error_mark_node) return false; if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE) @@ -2427,25 +2537,36 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) } /* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit - conversion from FROM to TO and return the result. */ + conversion from FROM to TO and return the result. If EXPLAIN, emit a + diagnostic about why the conversion failed. */ static tree -is_convertible_helper (tree from, tree to) +is_convertible_helper (tree from, tree to, bool explain) { if (VOID_TYPE_P (from) && VOID_TYPE_P (to)) return integer_one_node; cp_unevaluated u; - tree expr = build_trait_object (from); + tsubst_flags_t complain = explain ? tf_error : tf_none; + /* std::is_{,nothrow_}convertible test whether the imaginary function definition To test() { return std::declval<From>(); } is well-formed. A function can't return a function. */ - if (FUNC_OR_METHOD_TYPE_P (to) || expr == error_mark_node) + if (FUNC_OR_METHOD_TYPE_P (to)) + { + if (explain) + error ("%qT is a function type", to); + return error_mark_node; + } + + tree expr = build_trait_object (from, complain); + if (expr == error_mark_node) return error_mark_node; + deferring_access_check_sentinel acs (dk_no_deferred); - return perform_implicit_conversion (to, expr, tf_none); + return perform_implicit_conversion (to, expr, complain); } /* Return true if FROM can be converted to TO using implicit conversions, @@ -2454,9 +2575,9 @@ is_convertible_helper (tree from, tree to) to either type" restriction. */ bool -is_convertible (tree from, tree to) +is_convertible (tree from, tree to, bool explain/*=false*/) { - tree expr = is_convertible_helper (from, to); + tree expr = is_convertible_helper (from, to, explain); if (expr == error_mark_node) return false; return !!expr; @@ -2465,12 +2586,16 @@ is_convertible (tree from, tree to) /* Like is_convertible, but the conversion is also noexcept. */ bool -is_nothrow_convertible (tree from, tree to) +is_nothrow_convertible (tree from, tree to, bool explain/*=false*/) { - tree expr = is_convertible_helper (from, to); + tree expr = is_convertible_helper (from, to, explain); if (expr == NULL_TREE || expr == error_mark_node) return false; - return expr_noexcept_p (expr, tf_none); + + bool is_noexcept = expr_noexcept_p (expr, tf_none); + if (explain && !is_noexcept) + explain_not_noexcept (expr); + return is_noexcept; } /* Categorize various special_function_kinds. */ @@ -2949,7 +3074,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 +3114,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) @@ -3549,21 +3676,24 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn) the program is ill-formed" */ || !TYPE_REF_P (parmtype))); /* Decide if we want to emit a pedwarn, error, or a warning. */ - diagnostic_t diag_kind; + enum diagnostics::kind diag_kind; int opt; if (illformed_p) { - diag_kind = DK_ERROR; + diag_kind = diagnostics::kind::error; opt = 0; } else { - diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN; + diag_kind = (cxx_dialect >= cxx20 + ? diagnostics::kind::warning + : diagnostics::kind::pedwarn); opt = OPT_Wdefaulted_function_deleted; } /* Don't warn for template instantiations. */ - if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING) + if (DECL_TEMPLATE_INSTANTIATION (fn) + && diag_kind == diagnostics::kind::warning) return; const char *wmsg; @@ -3914,5 +4044,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..9412f78 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 *, diagnostics::context *, + unsigned *); + bool read_diagnostic_classification (diagnostics::context *); + private: void write_define (bytes_out &, const cpp_macro *); cpp_macro *read_define (bytes_in &, cpp_reader *) const; @@ -4814,7 +4822,8 @@ noisy_p () return false; pp_needs_newline (global_dc->get_reference_printer ()) = true; - diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL); + diagnostic_set_last_function (global_dc, + (diagnostics::diagnostic_info *) nullptr); return true; } @@ -5546,8 +5555,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 +5569,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 +5585,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 +5734,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 +6023,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 +6094,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; @@ -6159,7 +6158,7 @@ trees_out::lang_type_bools (tree t, bits_out& bits) WB (lang->declared_class); WB (lang->diamond_shaped); WB (lang->repeated_base); - gcc_assert (!lang->being_defined); + gcc_checking_assert (!lang->being_defined); // lang->debug_requested WB (lang->fields_readonly); WB (lang->ptrmemfunc_flag); @@ -6185,6 +6184,14 @@ trees_out::lang_type_bools (tree t, bits_out& bits) WB (lang->has_constexpr_ctor); WB (lang->unique_obj_representations); WB (lang->unique_obj_representations_set); + gcc_checking_assert (!lang->erroneous); + WB (lang->non_pod_aggregate); + WB (lang->non_aggregate_pod); + WB (lang->trivially_relocatable); + WB (lang->trivially_relocatable_computed); + + WB (lang->replaceable); + WB (lang->replaceable_computed); #undef WB } @@ -6229,8 +6236,8 @@ trees_in::lang_type_bools (tree t, bits_in& bits) RB (lang->declared_class); RB (lang->diamond_shaped); RB (lang->repeated_base); - gcc_assert (!lang->being_defined); - gcc_assert (!lang->debug_requested); + gcc_checking_assert (!lang->being_defined); + gcc_checking_assert (!lang->debug_requested); RB (lang->fields_readonly); RB (lang->ptrmemfunc_flag); @@ -6255,6 +6262,14 @@ trees_in::lang_type_bools (tree t, bits_in& bits) RB (lang->has_constexpr_ctor); RB (lang->unique_obj_representations); RB (lang->unique_obj_representations_set); + gcc_checking_assert (!lang->erroneous); + RB (lang->non_pod_aggregate); + RB (lang->non_aggregate_pod); + RB (lang->trivially_relocatable); + RB (lang->trivially_relocatable_computed); + + RB (lang->replaceable); + RB (lang->replaceable_computed); #undef RB return !get_overrun (); } @@ -6517,7 +6532,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); @@ -6542,8 +6560,14 @@ trees_out::core_vals (tree t) } WT (t->function_decl.personality); - WT (t->function_decl.function_specific_target); - WT (t->function_decl.function_specific_optimization); + /* Rather than streaming target/optimize nodes, we should reconstruct + them on stream-in from any attributes applied to the function. */ + if (streaming_p () && t->function_decl.function_specific_target) + warning_at (DECL_SOURCE_LOCATION (t), 0, + "%<target%> attribute currently unsupported in modules"); + if (streaming_p () && t->function_decl.function_specific_optimization) + warning_at (DECL_SOURCE_LOCATION (t), 0, + "%<optimize%> attribute currently unsupported in modules"); WT (t->function_decl.vindex); if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t)) @@ -6633,11 +6657,12 @@ trees_out::core_vals (tree t) case TARGET_OPTION_NODE: // FIXME: Our representation for these two nodes is a cache of // the resulting set of options. Not a record of the options - // that got changed by a particular attribute or pragma. Should - // we record that, or should we record the diff from the command - // line options? The latter seems the right behaviour, but is - // (a) harder, and I guess could introduce strangeness if the - // importer has set some incompatible set of optimization flags? + // that got changed by a particular attribute or pragma. Instead + // of recording that, we probably should just rebuild the options + // on stream-in from the function attributes. This could introduce + // strangeness if the importer has some incompatible set of flags + // but we currently assume users "know what they're doing" in such + // a case anyway. gcc_unreachable (); break; @@ -6784,6 +6809,13 @@ trees_out::core_vals (tree t) if (streaming_p ()) WU (((lang_tree_node *)t)->trait_expression.kind); break; + + case TU_LOCAL_ENTITY: + WT (((lang_tree_node *)t)->tu_local_entity.name); + if (state) + state->write_location + (*this, ((lang_tree_node *)t)->tu_local_entity.loc); + break; } if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) @@ -7089,8 +7121,10 @@ trees_in::core_vals (tree t) } RT (t->function_decl.personality); - RT (t->function_decl.function_specific_target); - RT (t->function_decl.function_specific_optimization); + /* These properties are not streamed, and should be reconstructed + from any function attributes. */ + // t->function_decl.function_specific_target); + // t->function_decl.function_specific_optimization); RT (t->function_decl.vindex); if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t)) @@ -7196,7 +7230,7 @@ trees_in::core_vals (tree t) case OPTIMIZATION_NODE: case TARGET_OPTION_NODE: - /* Not yet implemented, see trees_out::core_vals. */ + /* Not implemented, see trees_out::core_vals. */ gcc_unreachable (); break; @@ -7327,6 +7361,11 @@ trees_in::core_vals (tree t) RT (((lang_tree_node *)t)->trait_expression.type2); RUC (cp_trait_kind, ((lang_tree_node *)t)->trait_expression.kind); break; + + case TU_LOCAL_ENTITY: + RT (((lang_tree_node *)t)->tu_local_entity.name); + ((lang_tree_node *)t)->tu_local_entity.loc + = state->read_location (*this); } if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) @@ -7386,7 +7425,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 +7509,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 +8136,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 +8257,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 +9415,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 +9494,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 @@ -9592,6 +9657,8 @@ trees_out::type_node (tree type) tag_type = enum_type; else if (TYPENAME_IS_CLASS_P (type)) tag_type = class_type; + else if (TYPENAME_IS_UNION_P (type)) + tag_type = union_type; u (int (tag_type)); } } @@ -9645,11 +9712,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 +9731,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 +9740,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 +9829,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 +10020,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 +10041,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 +10126,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 +10139,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 +10287,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) @@ -10116,7 +10306,8 @@ trees_in::tree_node (bool is_use) && dump ("Read %stypedef %C:%N", DECL_IMPLICIT_TYPEDEF_P (res) ? "implicit " : "", TREE_CODE (res), res); - res = TREE_TYPE (res); + if (TREE_CODE (res) != TU_LOCAL_ENTITY) + res = TREE_TYPE (res); } break; @@ -10503,7 +10694,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; } @@ -10971,8 +11163,7 @@ trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn) { tree existing_parm = existing ? DECL_ARGUMENTS (existing) : NULL_TREE; tree parms = DECL_ARGUMENTS (fn); - unsigned ix = 0; - for (tree parm = parms; parm; parm = DECL_CHAIN (parm), ix++) + for (tree parm = parms; parm; parm = DECL_CHAIN (parm)) { if (existing_parm) { @@ -10982,6 +11173,20 @@ trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn) names of the parms from us. */ DECL_NAME (existing_parm) = DECL_NAME (parm); DECL_SOURCE_LOCATION (existing_parm) = DECL_SOURCE_LOCATION (parm); + + /* And some other flags important for codegen are only set + by the definition. */ + TREE_ADDRESSABLE (existing_parm) = TREE_ADDRESSABLE (parm); + DECL_BY_REFERENCE (existing_parm) = DECL_BY_REFERENCE (parm); + DECL_NONLOCAL (existing_parm) = DECL_NONLOCAL (parm); + DECL_ARG_TYPE (existing_parm) = DECL_ARG_TYPE (parm); + + /* Invisiref parms had their types adjusted by cp_genericize. */ + if (DECL_BY_REFERENCE (parm)) + { + TREE_TYPE (existing_parm) = TREE_TYPE (parm); + relayout_decl (existing_parm); + } } back_refs[~tag] = existing_parm; @@ -11110,6 +11315,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 +11332,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 +12301,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 +12312,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 +12333,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 +12375,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 +12390,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 +12438,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 +12461,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 +12860,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; @@ -13185,13 +13445,19 @@ trees_in::read_class_def (tree defn, tree maybe_template) if (TYPE_LANG_SPECIFIC (type)) { - CLASSTYPE_LAMBDA_EXPR (type) = lambda; + if (!TYPE_POLYMORPHIC_P (type)) + SET_CLASSTYPE_LAMBDA_EXPR (type, lambda); + else + gcc_checking_assert (lambda == NULL_TREE); CLASSTYPE_MEMBER_VEC (type) = member_vec; CLASSTYPE_PURE_VIRTUALS (type) = pure_virts; CLASSTYPE_VCALL_INDICES (type) = vcall_indices; - CLASSTYPE_KEY_METHOD (type) = key_method; + if (TYPE_POLYMORPHIC_P (type)) + SET_CLASSTYPE_KEY_METHOD (type, key_method); + else + gcc_checking_assert (key_method == NULL_TREE); CLASSTYPE_VBASECLASSES (type) = vbase_vec; @@ -14028,9 +14294,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 +15055,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 +15265,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 +17073,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 +17123,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 +17166,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 +17229,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 +17245,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 +18375,170 @@ 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 (enum diagnostics::kind dk) +{ + gcc_assert (dk > diagnostics::kind::unspecified + && dk < diagnostics::kind::last_diagnostic_kind); + if (dk == diagnostics::kind::ignored) + /* diagnostics/kinds.def has an empty string for ignored. */ + return "ignored: "; + else + return diagnostics::get_text_for_kind (dk); +} + +/* Dump one #pragma GCC diagnostic entry. */ + +static bool +dump_dc_change (unsigned index, unsigned opt, enum diagnostics::kind dk) +{ + if (dk == diagnostics::kind::pop) + return dump (" Index %u: pop from %d", index, opt); + else + return dump (" Index %u: %s%s", index, dk_string (dk), + 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, + diagnostics::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 diagnostics::kind::pop + targets to match the index in our actual output. So remember how many + lines we had skipped at each step, where -1 means this line itself + is skipped. */ + int skips = 0; + auto_vec<int> skips_at (len); + skips_at.safe_grow (len); + + 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 == diagnostics::kind::pop) + opt -= skips_at[opt]; + sec.u (opt); + sec.u (static_cast<unsigned> (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 (diagnostics::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 (); + enum diagnostics::kind kind = (enum diagnostics::kind) sec.u (); + if (kind == diagnostics::kind::pop) + /* For a pop, opt is the 'changes' index to return to. */ + opt += offset; + changes.quick_push ({ loc, opt, kind }); + 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 != diagnostics::kind::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, diagnostics::kind::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 +20225,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 +20372,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 +20448,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..ba62467 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. @@ -3351,8 +3351,12 @@ check_local_shadow (tree decl) } /* Don't complain if it's from an enclosing function. */ else if (DECL_CONTEXT (old) == current_function_decl - && TREE_CODE (decl) != PARM_DECL - && TREE_CODE (old) == PARM_DECL) + && ((TREE_CODE (decl) != PARM_DECL + && TREE_CODE (old) == PARM_DECL) + /* We should also give an error for + [x=1]{ int x; } */ + || (is_capture_proxy (old) + && !is_normal_capture_proxy (old)))) { /* Go to where the parms should be and see if we find them there. */ @@ -3408,7 +3412,9 @@ check_local_shadow (tree decl) detected elsewhere. */ else if (VAR_P (old) && old_scope == current_binding_level->level_chain - && (old_scope->kind == sk_cond || old_scope->kind == sk_for)) + && (old_scope->kind == sk_cond + || old_scope->kind == sk_for + || old_scope->kind == sk_template_for)) { if (name_independent_decl_p (decl)) return old; @@ -4178,22 +4184,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 +4562,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 +4575,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; @@ -4622,6 +4632,7 @@ cp_binding_level_descriptor (cp_binding_level *scope) "try-scope", "catch-scope", "for-scope", + "template-for-scope", "cond-init-scope", "stmt-expr-scope", "function-parameter-scope", @@ -4631,7 +4642,8 @@ cp_binding_level_descriptor (cp_binding_level *scope) "template-parameter-scope", "template-explicit-spec-scope", "transaction-scope", - "openmp-scope" + "openmp-scope", + "lambda-scope" }; static_assert (ARRAY_SIZE (scope_kind_names) == sk_count, "must keep names aligned with scope_kind enum"); @@ -4716,12 +4728,14 @@ begin_scope (scope_kind kind, tree entity) case sk_try: case sk_catch: case sk_for: + case sk_template_for: case sk_cond: case sk_class: case sk_scoped_enum: case sk_transaction: case sk_omp: case sk_stmt_expr: + case sk_lambda: scope->keep = keep_next_level_flag; break; @@ -5343,7 +5357,8 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, OVL_EXPORT_P (old.get_using ()) = true; } else if (!DECL_LANG_SPECIFIC (inner) - || !DECL_MODULE_PURVIEW_P (inner)) + || !DECL_MODULE_PURVIEW_P (inner) + || (exporting_p && !DECL_MODULE_EXPORT_P (inner))) /* We need to re-insert this function as a revealed (possibly exported) declaration. We can't remove the existing decl because that will change any @@ -5365,7 +5380,8 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, found = true; if (revealing_p && (!DECL_LANG_SPECIFIC (inner) - || !DECL_MODULE_PURVIEW_P (inner))) + || !DECL_MODULE_PURVIEW_P (inner) + || (exporting_p && !DECL_MODULE_EXPORT_P (inner)))) found = false; break; } @@ -6864,7 +6880,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 +7100,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 +7129,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; } @@ -7187,13 +7207,14 @@ suggest_alternatives_for_1 (location_t location, tree name, /* Look for exact matches for builtin defines that would have been defined if the user had passed a command-line option (e.g. -fopenmp for "_OPENMP"). */ - diagnostic_option_id option_id + diagnostics::option_id option_id = get_option_for_builtin_define (IDENTIFIER_POINTER (name)); if (option_id.m_idx > 0) - return name_hint (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 +7342,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 +7726,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 +7739,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 +7810,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 +8955,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..5b142e7 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -198,6 +198,7 @@ enum scope_kind { sk_catch, /* A catch-block. */ sk_for, /* The scope of the variable declared in a init-statement. */ + sk_template_for, /* Ditto for expansion statements. */ sk_cond, /* The scope of the variable declared in the condition of an if or switch statement. */ sk_stmt_expr, /* GNU statement expression block. */ @@ -214,6 +215,7 @@ enum scope_kind { "template <>", this scope is always empty. */ sk_transaction, /* A synchronized or atomic statement. */ sk_omp, /* An OpenMP structured block. */ + sk_lambda, /* A lambda scope. */ sk_count /* Number of scope_kind enumerations. */ }; @@ -287,7 +289,7 @@ struct GTY(()) cp_binding_level { /* The kind of scope that this object represents. However, a SK_TEMPLATE_SPEC scope is represented with KIND set to SK_TEMPLATE_PARMS and EXPLICIT_SPEC_P set to true. */ - ENUM_BITFIELD (scope_kind) kind : 4; + ENUM_BITFIELD (scope_kind) kind : 5; /* True if this scope is an SK_TEMPLATE_SPEC scope. This field is only valid if KIND == SK_TEMPLATE_PARMS. */ @@ -315,7 +317,7 @@ struct GTY(()) cp_binding_level { parent scope. */ unsigned artificial : 1; - /* 21 bits left to fill a 32-bit word. */ + /* 20 bits left to fill a 32-bit word. */ }; /* The binding level currently in effect. */ @@ -462,6 +464,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 +503,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..9f9bd56 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 @@ -569,6 +601,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) parser->in_template_argument_list_p); cp_debug_print_flag (file, "Parsing an iteration statement", parser->in_statement & IN_ITERATION_STMT); + cp_debug_print_flag (file, "Parsing an expansion statement", + parser->in_statement & IN_EXPANSION_STMT); cp_debug_print_flag (file, "Parsing a switch statement", parser->in_statement & IN_SWITCH_STMT); cp_debug_print_flag (file, "Parsing a structured OpenMP block", @@ -2487,7 +2521,7 @@ static cp_expr cp_parser_id_expression static cp_expr cp_parser_unqualified_id (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt - (cp_parser *, bool, bool, bool, bool, bool = false); + (cp_parser *, bool, bool, bool, bool, bool = false, bool = false); static tree cp_parser_nested_name_specifier (cp_parser *, bool, bool, bool, bool); static tree cp_parser_qualifying_entity @@ -2544,11 +2578,11 @@ static cp_expr cp_parser_constant_expression static cp_expr cp_parser_builtin_offsetof (cp_parser *); static cp_expr cp_parser_lambda_expression - (cp_parser *); + (cp_parser *, bool = false); static void cp_parser_lambda_introducer (cp_parser *, tree); static bool cp_parser_lambda_declarator_opt - (cp_parser *, tree); + (cp_parser *, tree, bool = false); static void cp_parser_lambda_body (cp_parser *, tree); @@ -2579,11 +2613,11 @@ static tree cp_parser_c_for static tree cp_parser_range_for (cp_parser *, tree, tree, tree, bool, tree, bool, bool); static void do_range_for_auto_deduction - (tree, tree, cp_decomp *); -static tree cp_parser_perform_range_for_lookup - (tree, tree *, tree *); -static tree cp_parser_range_for_member_function + (tree, tree, cp_decomp *, bool); +static tree cp_range_for_member_function (tree, tree); +static tree cp_parser_expansion_statement + (cp_parser *, bool *); static tree cp_parser_jump_statement (cp_parser *, tree &); static void cp_parser_declaration_statement @@ -2889,7 +2923,7 @@ static size_t cp_parser_skip_std_attribute_spec_seq static size_t cp_parser_skip_attributes_opt (cp_parser *, size_t); static bool cp_parser_extension_opt - (cp_parser *, int *); + (cp_parser *, int *, int *); static void cp_parser_label_declaration (cp_parser *); @@ -3059,8 +3093,8 @@ static cp_token *cp_parser_require_keyword (cp_parser *, enum rid, required_token); static bool cp_parser_token_starts_function_definition_p (cp_token *); -static bool cp_parser_next_token_starts_class_definition_p - (cp_parser *); +static bool cp_parser_nth_token_starts_class_definition_p + (cp_parser *, size_t); static bool cp_parser_next_token_ends_template_argument_p (cp_parser *); static bool cp_parser_nth_token_starts_template_argument_list_p @@ -3434,9 +3468,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. */ @@ -5232,7 +5268,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) && (id_equal (suffix_id, "i") || id_equal (suffix_id, "if") || id_equal (suffix_id, "il"))); - diagnostic_t kind = DK_ERROR; + enum diagnostics::kind kind = diagnostics::kind::error; int opt = 0; if (i14 && ext) @@ -5242,7 +5278,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) if (cxlit == error_mark_node) { /* No <complex>, so pedwarn and use GNU semantics. */ - kind = DK_PEDWARN; + kind = diagnostics::kind::pedwarn; opt = OPT_Wpedantic; } } @@ -5269,7 +5305,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) "to enable more built-in suffixes"); } - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) value = error_mark_node; else { @@ -5469,6 +5505,14 @@ cp_parser_translation_unit (cp_parser* parser) cp_parser_toplevel_declaration (parser); } +#if ENABLE_ANALYZER + if (flag_analyzer) + { + ana::cp_translation_unit tu; + ana::on_finish_translation_unit (tu); + } +#endif + /* Get rid of the token array; we don't need it any more. */ cp_lexer_destroy (parser->lexer); parser->lexer = NULL; @@ -6265,7 +6309,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Recognize the `this' keyword. */ case RID_THIS: cp_lexer_consume_token (parser->lexer); - if (parser->local_variables_forbidden_p & THIS_FORBIDDEN) + if ((parser->local_variables_forbidden_p & THIS_FORBIDDEN) + /* It's OK to refer to 'this' in an unevaluated operand in a + lambda default argument (lambda-targ16.C). */ + && !cp_unevaluated_operand) { error_at (token->location, "%<this%> may not be used in this context"); @@ -6602,7 +6649,8 @@ cp_parser_primary_expression (cp_parser *parser, member template. */ static void -missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING) +missing_template_diag (location_t loc, + enum diagnostics::kind diag_kind = diagnostics::kind::warning) { if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword)) return; @@ -7197,18 +7245,22 @@ check_template_keyword_in_nested_name_spec (tree name) nested-name-specifier template [opt] simple-template-id :: PARSER->SCOPE should be set appropriately before this function is - called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in - effect. TYPE_P is TRUE if we non-type bindings should be ignored - in name lookups. + called. TYPENAME_KEYWORD_P is true if the `typename' keyword is in + effect. TYPE_P is true if we non-type bindings should be ignored + in name lookups. TEMPLATE_KEYWORD_P is true if the `template' keyword + was seen. GLOBAL_P is true if `::' has already been parsed. + TODO: This function doesn't handle the C++14 change to make `::' + a nested-name-specifier by itself. If it did, GLOBAL_P could probably + go. Sets PARSER->SCOPE to the class (TYPE) or namespace (NAMESPACE_DECL) specified by the nested-name-specifier, or leaves it unchanged if there is no nested-name-specifier. Returns the new scope iff there is a nested-name-specifier, or NULL_TREE otherwise. - If CHECK_DEPENDENCY_P is FALSE, names are looked up in dependent scopes. + If CHECK_DEPENDENCY_P is false, names are looked up in dependent scopes. - If IS_DECLARATION is TRUE, the nested-name-specifier is known to be + If IS_DECLARATION is true, the nested-name-specifier is known to be part of a declaration and/or decl-specifier. */ static tree @@ -7217,7 +7269,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, bool check_dependency_p, bool type_p, bool is_declaration, - bool template_keyword_p /* = false */) + bool template_keyword_p /* = false */, + bool global_p /* = false */) { bool success = false; cp_token_position start = 0; @@ -7265,8 +7318,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, /* Spot cases that cannot be the beginning of a nested-name-specifier. On the second and subsequent times - through the loop, we look for the `template' keyword. */ - if (success && token->keyword == RID_TEMPLATE) + (or the first, if '::' has already been parsed) through the + loop, we look for the `template' keyword. */ + if ((success || global_p) && token->keyword == RID_TEMPLATE) ; /* A template-id can start a nested-name-specifier. */ else if (token->type == CPP_TEMPLATE_ID) @@ -7314,8 +7368,11 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, cp_parser_parse_tentatively (parser); /* Look for the optional `template' keyword, if this isn't the - first time through the loop. */ - if (success) + first time through the loop, or if we've already parsed '::'; + this is then the + nested-name-specifier template [opt] simple-template-id :: + production. */ + if (success || global_p) { template_keyword_p = cp_parser_optional_template_keyword (parser); /* DR1710: "In a qualified-id used as the name in @@ -8800,8 +8857,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, { /* In a template, be permissive by treating an object expression of incomplete type as dependent (after a pedwarn). */ - diagnostic_t kind = (processing_template_decl - && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR); + enum diagnostics::kind kind = ((processing_template_decl + && MAYBE_CLASS_TYPE_P (*scope)) + ? diagnostics::kind::pedwarn + : diagnostics::kind::error); switch (TREE_CODE (*postfix_expression)) { @@ -8813,27 +8872,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression, case IMPLICIT_CONV_EXPR: case VIEW_CONVERT_EXPR: case NON_LVALUE_EXPR: - kind = DK_ERROR; + kind = diagnostics::kind::error; break; case OVERLOAD: /* Don't emit any diagnostic for OVERLOADs. */ - kind = DK_IGNORED; + kind = diagnostics::kind::ignored; break; default: /* Avoid clobbering e.g. DECLs. */ if (!EXPR_P (*postfix_expression)) - kind = DK_ERROR; + kind = diagnostics::kind::error; break; } - if (kind == DK_IGNORED) + if (kind == diagnostics::kind::ignored) return false; location_t exploc = location_of (*postfix_expression); cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind); if (!MAYBE_CLASS_TYPE_P (*scope)) return true; - if (kind == DK_ERROR) + if (kind == diagnostics::kind::error) *scope = *postfix_expression = error_mark_node; else if (processing_template_decl) { @@ -9447,21 +9506,23 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, case RID_EXTENSION: { /* The saved value of the PEDANTIC flag. */ - int saved_pedantic; + int saved_pedantic, saved_long_long; tree expr; /* Save away the PEDANTIC flag. */ - cp_parser_extension_opt (parser, &saved_pedantic); + cp_parser_extension_opt (parser, &saved_pedantic, + &saved_long_long); /* Also suppress -Wconditionally-supported. */ diagnostic_push_diagnostics (global_dc, input_location); diagnostic_classify_diagnostic (global_dc, OPT_Wconditionally_supported, - DK_IGNORED, input_location); + diagnostics::kind::ignored, input_location); /* Parse the cast-expression. */ expr = cp_parser_simple_cast_expression (parser); /* Restore the PEDANTIC flag. */ diagnostic_pop_diagnostics (global_dc, input_location); pedantic = saved_pedantic; + warn_long_long = saved_long_long; return expr; } @@ -10793,6 +10854,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; @@ -11677,10 +11746,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* trait) lambda-introducer < template-parameter-list > requires-clause [opt] lambda-declarator [opt] compound-statement + If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which + is syntactic sugar for a consteval lambda. + Returns a representation of the expression. */ static cp_expr -cp_parser_lambda_expression (cp_parser* parser) +cp_parser_lambda_expression (cp_parser* parser, + bool consteval_block_p/*=false*/) { tree lambda_expr = build_lambda_expr (); tree type; @@ -11689,6 +11762,7 @@ cp_parser_lambda_expression (cp_parser* parser) cp_token_position start = 0; LAMBDA_EXPR_LOCATION (lambda_expr) = token->location; + LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lambda_expr) = consteval_block_p; if (cxx_dialect >= cxx20) { @@ -11732,9 +11806,14 @@ cp_parser_lambda_expression (cp_parser* parser) it now. */ push_deferring_access_checks (dk_no_deferred); - cp_parser_lambda_introducer (parser, lambda_expr); - if (cp_parser_error_occurred (parser)) - return error_mark_node; + auto gr = make_temp_override (parser->greater_than_is_operator_p, true); + + if (!consteval_block_p) + { + cp_parser_lambda_introducer (parser, lambda_expr); + if (cp_parser_error_occurred (parser)) + return error_mark_node; + } { /* OK, this is a bit tricksy. cp_parser_requires_expression sets @@ -11776,6 +11855,7 @@ cp_parser_lambda_expression (cp_parser* parser) bool auto_is_implicit_function_template_parm_p = parser->auto_is_implicit_function_template_parm_p; bool saved_omp_array_section_p = parser->omp_array_section_p; + bool saved_in_targ = parser->in_template_argument_list_p; parser->num_template_parameter_lists = 0; parser->in_statement = 0; @@ -11785,6 +11865,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->implicit_template_scope = 0; parser->auto_is_implicit_function_template_parm_p = false; parser->omp_array_section_p = false; + parser->in_template_argument_list_p = false; /* Inside the lambda, outside unevaluated context do not apply. */ cp_evaluated ev; @@ -11798,13 +11879,22 @@ cp_parser_lambda_expression (cp_parser* parser) bool save_in_consteval_if_p = in_consteval_if_p; in_consteval_if_p = false; + /* Similarly the body of a lambda is not part of expansion statement. */ + bool save_in_expansion_stmt = in_expansion_stmt; + in_expansion_stmt = 0; + /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ if (cp_parser_start_tentative_firewall (parser)) start = token; - ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr); + /* A lambda scope starts immediately after the lambda-introducer of E + and extends to the end of the compound-statement of E. */ + begin_scope (sk_lambda, NULL_TREE); + + ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr, + consteval_block_p); if (ok && cp_parser_error_occurred (parser)) ok = false; @@ -11824,8 +11914,11 @@ cp_parser_lambda_expression (cp_parser* parser) if (ok) maybe_add_lambda_conv_op (type); + /* Leave the lambda scope. */ + pop_bindings_and_leave_scope (); finish_struct (type, /*attributes=*/NULL_TREE); + in_expansion_stmt = save_in_expansion_stmt; in_consteval_if_p = save_in_consteval_if_p; in_discarded_stmt = discarded; @@ -11839,6 +11932,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->auto_is_implicit_function_template_parm_p = auto_is_implicit_function_template_parm_p; parser->omp_array_section_p = saved_omp_array_section_p; + parser->in_template_argument_list_p = saved_in_targ; } /* This lambda shouldn't have any proxies left at this point. */ @@ -12186,10 +12280,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) decl-specifier-seq [opt] noexcept-specifier [opt] attribute-specifier-seq [opt] trailing-return-type [opt] - LAMBDA_EXPR is the current representation of the lambda expression. */ + LAMBDA_EXPR is the current representation of the lambda expression. + If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which + is syntactic sugar for a consteval lambda. */ static bool -cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) +cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr, + bool consteval_block_p/*=false*/) { /* 5.1.1.4 of the standard says: If a lambda-expression does not include a lambda-declarator, it is as if @@ -12210,6 +12307,13 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) clear_decl_specs (&lambda_specs); /* A lambda op() is const unless explicitly 'mutable'. */ cp_cv_quals quals = TYPE_QUAL_CONST; + /* Don't add "const" to entities in the parameter-declaration-clause. */ + LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = false; + + /* Inject the captures into the lambda scope as they may be used in the + declarator and we have to be able to look them up. */ + tree dummy_fco = maybe_add_dummy_lambda_op (lambda_expr); + push_capture_proxies (lambda_expr, /*early_p=*/true); /* The template-parameter-list is optional, but must begin with an opening angle if present. */ @@ -12292,6 +12396,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR, &lambda_specs, &declares_class_or_enum); + /* [dcl.pre] For a consteval-block-declaration D, the expression E + corresponding to D is: + [] -> void static consteval compound-statement () + Make it so. */ + if (consteval_block_p) + { + return_type = void_type_node; + lambda_specs.storage_class = sc_static; + set_and_check_decl_spec_loc (&lambda_specs, ds_consteval, + cp_lexer_peek_token (parser->lexer)); + } + if (omitted_parms_loc && lambda_specs.any_specifiers_p) { pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, @@ -12388,6 +12504,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) } } + /* Now we're done with the parameter-declaration-clause, and should + assume "const" unless "mutable" was present. */ + LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = quals == TYPE_QUAL_CONST; + tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) { @@ -12445,6 +12565,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) pop_bindings_and_leave_scope (); } + /* We are about to create the real operator(), so get rid of the old one. */ + if (dummy_fco) + remove_dummy_lambda_op (dummy_fco, lambda_expr); + /* Create the function call operator. Messing with declarators like this is no uglier than building up the @@ -12524,6 +12648,79 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) } } +/* Create a fake operator() for a lambda. We do this so that we can + build_capture_proxy even before start_lambda_function. */ + +static tree +make_dummy_lambda_op () +{ + cp_decl_specifier_seq return_type_specs; + cp_cv_quals quals = TYPE_UNQUALIFIED; + + clear_decl_specs (&return_type_specs); + return_type_specs.type = make_auto (); + + void *p = obstack_alloc (&declarator_obstack, 0); + + cp_declarator *declarator = make_id_declarator (NULL_TREE, + call_op_identifier, + sfk_none, + input_location); + + declarator = make_call_declarator (declarator, void_list_node, quals, + VIRT_SPEC_UNSPECIFIED, + REF_QUAL_NONE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, + NULL_TREE, UNKNOWN_LOCATION); + + tree fco = grokmethod (&return_type_specs, declarator, NULL_TREE); + obstack_free (&declarator_obstack, p); + + return fco; +} + +/* We need to push early capture proxies (for parsing the lambda-declarator), + and we may need a dummy operator() to be able to build the proxies. + LAMBDA_EXPR is the lambda we are building the captures for. */ + +tree +maybe_add_dummy_lambda_op (tree lambda_expr) +{ + /* If there are no captures, we don't need this. */ + if (!LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)) + return NULL_TREE; + + tree fco = make_dummy_lambda_op (); + if (fco != error_mark_node) + finish_member_declaration (fco); + + return fco; +} + +/* Remove the dummy operator() DUMMY_FCO we built for parsing the + lambda-declarator of LAMBDA_EXPR. */ + +void +remove_dummy_lambda_op (tree dummy_fco, tree lambda_expr) +{ + tree type = TREE_TYPE (lambda_expr); + if (TYPE_FIELDS (type) == dummy_fco) + { + /* Stitch out the dummy operator(). */ + TYPE_FIELDS (type) = DECL_CHAIN (TYPE_FIELDS (type)); + /* And clear the member vector as well. */ + auto *member_vec = CLASSTYPE_MEMBER_VEC (type); + gcc_assert (member_vec->length () == 1); + member_vec->truncate (0); + } + /* Class templates will have the dummy operator() stashed here too. */ + tree &list = CLASSTYPE_DECL_LIST (type); + if (list && TREE_VALUE (list) == dummy_fco) + list = TREE_CHAIN (list); + /* ??? We can't ggc_free dummy_fco yet. There's still a binding in the + closure to it, and the captures have it as their DECL_CONTEXT. */ +} + /* Parse the body of a lambda expression, which is simply compound-statement @@ -13070,6 +13267,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_TRANSACTION_CANCEL: handle_omp_attribs = true; break; + case RID_TEMPLATE: + if (cxx_dialect >= cxx11 + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)) + handle_omp_attribs = true; + break; default: break; } @@ -13122,6 +13324,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, NULL_TREE, false); break; + case RID_TEMPLATE: + if (cxx_dialect >= cxx11 + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)) + { + std_attrs = process_stmt_hotness_attribute (std_attrs, + attrs_loc); + statement = cp_parser_expansion_statement (parser, if_p); + } + break; + case RID_BREAK: case RID_CONTINUE: case RID_RETURN: @@ -13524,6 +13736,13 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) default: /* Anything else must be an ordinary label. */ cp_expr identifier = cp_parser_identifier (parser); + if (in_expansion_stmt && identifier != error_mark_node) + { + error_at (token->location, + "identifier label %qE in %<template for%> body", + *identifier); + break; + } if (identifier != error_mark_node && parser->omp_metadirective_state) *identifier = mangle_metadirective_region_label (parser, *identifier); @@ -14550,6 +14769,73 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, return stmt; } +/* Helper function for cp_parser_range_for and cp_parser_expansion_statement. + Get the range declaration momentarily out of the way so that the range + expression doesn't clash with it. */ + +static cp_decomp * +cp_hide_range_decl (tree *range_decl_p, cp_decomp *decomp_d, + auto_vec <cxx_binding *> &bindings, + auto_vec <tree> &names) +{ + tree range_decl = *range_decl_p; + cp_decomp *decomp = NULL; + if (range_decl == error_mark_node) + return decomp; + + if (DECL_HAS_VALUE_EXPR_P (range_decl)) + { + tree v = DECL_VALUE_EXPR (range_decl); + /* For decomposition declaration get all of the corresponding + declarations out of the way. */ + if ((TREE_CODE (v) == ARRAY_REF + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + || (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))) + { + tree d = range_decl; + decomp = decomp_d; + if (TREE_CODE (v) == ARRAY_REF) + { + *range_decl_p = range_decl = TREE_OPERAND (v, 0); + decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + } + else + { + *range_decl_p = range_decl = TREE_VEC_ELT (v, 0); + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + } + decomp->decl = d; + bool seen_name_independent_decl = false; + names.reserve (decomp->count); + bindings.reserve (decomp->count); + for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d)) + { + if (name_independent_decl_p (d)) + { + /* If there is more than one _ decl in the structured + binding, just push and move it away once. */ + if (seen_name_independent_decl) + continue; + seen_name_independent_decl = true; + } + tree name = DECL_NAME (d); + names.quick_push (name); + bindings.quick_push (IDENTIFIER_BINDING (name)); + IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; + } + } + } + if (names.is_empty ()) + { + tree name = DECL_NAME (range_decl); + names.safe_push (name); + bindings.safe_push (IDENTIFIER_BINDING (name)); + IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; + } + return decomp; +} + /* Tries to parse a range-based for-statement: range-based-for: @@ -14565,56 +14851,14 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, bool ivdep, tree unroll, bool novector, bool is_omp) { tree stmt, range_expr; - auto_vec <cxx_binding *, 16> bindings; - auto_vec <tree, 16> names; - cp_decomp decomp_d, *decomp = NULL; + auto_vec <cxx_binding *> bindings; + auto_vec <tree> names; + cp_decomp decomp_d; /* Get the range declaration momentarily out of the way so that the range expression doesn't clash with it. */ - if (range_decl != error_mark_node) - { - if (DECL_HAS_VALUE_EXPR_P (range_decl)) - { - tree v = DECL_VALUE_EXPR (range_decl); - /* For decomposition declaration get all of the corresponding - declarations out of the way. */ - if (TREE_CODE (v) == ARRAY_REF - && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) - { - tree d = range_decl; - range_decl = TREE_OPERAND (v, 0); - decomp = &decomp_d; - decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; - decomp->decl = d; - bool seen_name_independent_decl = false; - for (unsigned int i = 0; i < decomp->count; - i++, d = DECL_CHAIN (d)) - { - if (name_independent_decl_p (d)) - { - /* If there is more than one _ decl in - the structured binding, just push and move it - away once. */ - if (seen_name_independent_decl) - continue; - seen_name_independent_decl = true; - } - tree name = DECL_NAME (d); - names.safe_push (name); - bindings.safe_push (IDENTIFIER_BINDING (name)); - IDENTIFIER_BINDING (name) - = IDENTIFIER_BINDING (name)->previous; - } - } - } - if (names.is_empty ()) - { - tree name = DECL_NAME (range_decl); - names.safe_push (name); - bindings.safe_push (IDENTIFIER_BINDING (name)); - IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; - } - } + cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings, + names); if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) range_expr = cp_parser_braced_list (parser); @@ -14651,7 +14895,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ && !BRACE_ENCLOSED_INITIALIZER_P (range_expr)) - do_range_for_auto_deduction (range_decl, range_expr, decomp); + do_range_for_auto_deduction (range_decl, range_expr, decomp, false); } else { @@ -14665,7 +14909,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, /* Subroutine of cp_convert_range_for: given the initializer expression, builds up the range temporary. */ -static tree +tree build_range_temp (tree range_expr) { /* Find out the type deduced by the declaration @@ -14689,15 +14933,22 @@ build_range_temp (tree range_expr) a shortcut version of cp_convert_range_for. */ static void -do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp) +do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp, + bool expansion_stmt) { tree auto_node = type_uses_auto (TREE_TYPE (decl)); if (auto_node) { tree begin_dummy, end_dummy, range_temp, iter_type, iter_decl; range_temp = convert_from_reference (build_range_temp (range_expr)); - iter_type = (cp_parser_perform_range_for_lookup - (range_temp, &begin_dummy, &end_dummy)); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_dummy, + &end_dummy, + expansion_stmt ? tf_none + : tf_warning_or_error); + if (expansion_stmt + && (begin_dummy == error_mark_node + || end_dummy == error_mark_node)) + return; if (iter_type) { iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE, @@ -14798,6 +15049,89 @@ warn_for_range_copy (tree decl, tree expr) } } +/* Helper function for cp_convert_range_for and finish_expansion_stmt. + Build the __range, __begin and __end declarations. Return the + __begin VAR_DECL, set *END_P to the __end VAR_DECL. */ + +tree +cp_build_range_for_decls (location_t loc, tree range_expr, tree *end_p, + bool expansion_stmt_p) +{ + tree iter_type, begin_expr, end_expr; + + if (range_expr == error_mark_node) + /* If an error happened previously do nothing or else a lot of + unhelpful errors would be issued. */ + begin_expr = end_expr = iter_type = error_mark_node; + else + { + tree range_temp; + + if (!expansion_stmt_p + && VAR_P (range_expr) + && array_of_runtime_bound_p (TREE_TYPE (range_expr))) + /* Can't bind a reference to an array of runtime bound. */ + range_temp = range_expr; + else + { + range_temp = build_range_temp (range_expr); + if (expansion_stmt_p) + { + /* Depending on CWG3044 resolution, we might want to remove + these 3 sets of TREE_STATIC (on range_temp, begin and end). + Although it can only be done when P2686R4 is fully + implemented. */ + TREE_STATIC (range_temp) = 1; + TREE_PUBLIC (range_temp) = 0; + DECL_COMMON (range_temp) = 0; + DECL_INTERFACE_KNOWN (range_temp) = 1; + DECL_DECLARED_CONSTEXPR_P (range_temp) = 1; + TREE_READONLY (range_temp) = 1; + } + pushdecl (range_temp); + cp_finish_decl (range_temp, range_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + range_temp = convert_from_reference (range_temp); + } + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr); + } + + /* The new for initialization statement. */ + tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type); + TREE_USED (begin) = 1; + DECL_ARTIFICIAL (begin) = 1; + if (expansion_stmt_p) + { + TREE_STATIC (begin) = 1; + DECL_DECLARED_CONSTEXPR_P (begin) = 1; + TREE_READONLY (begin) = 1; + } + pushdecl (begin); + cp_finish_decl (begin, begin_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + + if (cxx_dialect >= cxx17) + iter_type = cv_unqualified (TREE_TYPE (end_expr)); + tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type); + TREE_USED (end) = 1; + DECL_ARTIFICIAL (end) = 1; + if (expansion_stmt_p) + { + TREE_STATIC (end) = 1; + DECL_DECLARED_CONSTEXPR_P (end) = 1; + TREE_READONLY (end) = 1; + } + pushdecl (end); + cp_finish_decl (end, end_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + *end_p = end; + return begin; +} + /* Converts a range-based for-statement into a normal for-statement, as per the definition. @@ -14838,56 +15172,14 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, cp_decomp *decomp, bool ivdep, tree unroll, bool novector) { - tree begin, end; - tree iter_type, begin_expr, end_expr; - tree condition, expression; + tree end, condition, expression; range_expr = mark_lvalue_use (range_expr); - if (range_decl == error_mark_node || range_expr == error_mark_node) - /* If an error happened previously do nothing or else a lot of - unhelpful errors would be issued. */ - begin_expr = end_expr = iter_type = error_mark_node; - else - { - tree range_temp; - - if (VAR_P (range_expr) - && array_of_runtime_bound_p (TREE_TYPE (range_expr))) - /* Can't bind a reference to an array of runtime bound. */ - range_temp = range_expr; - else - { - range_temp = build_range_temp (range_expr); - pushdecl (range_temp); - cp_finish_decl (range_temp, range_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); - range_temp = convert_from_reference (range_temp); - } - iter_type = cp_parser_perform_range_for_lookup (range_temp, - &begin_expr, &end_expr); - } - - /* The new for initialization statement. */ - begin = build_decl (input_location, VAR_DECL, for_begin__identifier, - iter_type); - TREE_USED (begin) = 1; - DECL_ARTIFICIAL (begin) = 1; - pushdecl (begin); - cp_finish_decl (begin, begin_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); - - if (cxx_dialect >= cxx17) - iter_type = cv_unqualified (TREE_TYPE (end_expr)); - end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type); - TREE_USED (end) = 1; - DECL_ARTIFICIAL (end) = 1; - pushdecl (end); - cp_finish_decl (end, end_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); + if (range_decl == error_mark_node) + range_expr = error_mark_node; + tree begin + = cp_build_range_for_decls (input_location, range_expr, &end, false); finish_init_stmt (statement); @@ -14921,8 +15213,10 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, depends on the existence of members begin or end. Returns the type deduced for the iterator expression. */ -static tree -cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) +tree +cp_perform_range_for_lookup (tree range, tree *begin, tree *end, + tsubst_flags_t complain + /* = tf_warning_or_error */) { if (error_operand_p (range)) { @@ -14932,8 +15226,9 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range)))) { - error ("range-based %<for%> expression of type %qT " - "has incomplete type", TREE_TYPE (range)); + if (complain & tf_error) + error ("range-based %<for%> expression of type %qT " + "has incomplete type", TREE_TYPE (range)); *begin = *end = error_mark_node; return error_mark_node; } @@ -14959,16 +15254,16 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) id_end = get_identifier ("end"); member_begin = lookup_member (TREE_TYPE (range), id_begin, /*protect=*/2, /*want_type=*/false, - tf_warning_or_error); + complain); member_end = lookup_member (TREE_TYPE (range), id_end, /*protect=*/2, /*want_type=*/false, - tf_warning_or_error); + complain); if (member_begin != NULL_TREE && member_end != NULL_TREE) { /* Use the member functions. */ - *begin = cp_parser_range_for_member_function (range, id_begin); - *end = cp_parser_range_for_member_function (range, id_end); + *begin = cp_range_for_member_function (range, id_begin); + *end = cp_range_for_member_function (range, id_end); } else { @@ -14978,13 +15273,20 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) vec_safe_push (vec, range); member_begin = perform_koenig_lookup (id_begin, vec, - tf_warning_or_error); + complain); + if ((complain & tf_error) == 0 && member_begin == id_begin) + return error_mark_node; *begin = finish_call_expr (member_begin, &vec, false, true, - tf_warning_or_error); + complain); member_end = perform_koenig_lookup (id_end, vec, tf_warning_or_error); + if ((complain & tf_error) == 0 && member_end == id_end) + { + *begin = error_mark_node; + return error_mark_node; + } *end = finish_call_expr (member_end, &vec, false, true, - tf_warning_or_error); + complain); } /* Last common checks. */ @@ -15015,7 +15317,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) /* P0184R0 allows __begin and __end to have different types, but make sure they are comparable so we can give a better diagnostic. */; - else + else if (complain & tf_error) error ("inconsistent begin/end types in range-based %<for%> " "statement: %qT and %qT", TREE_TYPE (*begin), TREE_TYPE (*end)); @@ -15025,11 +15327,11 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) } } -/* Helper function for cp_parser_perform_range_for_lookup. +/* Helper function for cp_perform_range_for_lookup. Builds a tree for RANGE.IDENTIFIER(). */ static tree -cp_parser_range_for_member_function (tree range, tree identifier) +cp_range_for_member_function (tree range, tree identifier) { tree member, res; @@ -15248,6 +15550,183 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) return false; } +/* Parse an expansion-statement. + + expansion-statement: + template for ( init-statement[opt] + for-range-declaration : expansion-initializer ) + statement + + expansion-initializer: + expression + expansion-init-list + + expansion-init-list: + { expression-list } */ + +static tree +cp_parser_expansion_statement (cp_parser* parser, bool *if_p) +{ + /* Peek at the next token. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + gcc_assert (token->keyword == RID_TEMPLATE); + gcc_assert (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR)); + cp_lexer_consume_token (parser->lexer); + cp_token *for_token = cp_lexer_peek_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + + if (cxx_dialect < cxx26) + pedwarn (make_location (token->location, token->location, + for_token->location), OPT_Wc__26_extensions, + "%<template for%> only available with %<-std=c++2c%> " + "or %<-std=gnu++2c%>"); + + token_indent_info guard_tinfo = get_token_indent_info (token); + + /* Remember whether or not we are already within an iteration + statement. */ + unsigned char in_statement = parser->in_statement; + /* And whether we are already in expansion-statement. */ + auto save_in_expansion_stmt = in_expansion_stmt; + + /* Look for the `('. */ + matching_parens parens; + parens.require_open (parser); + + tree init; + tree scope = begin_template_for_scope (&init); + + /* Maybe parse the optional init-statement in a expansion-statement. */ + if (cp_parser_range_based_for_with_init_p (parser) + /* Checked for diagnostic purposes only. */ + && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + { + tree dummy; + cp_parser_init_statement (parser, &dummy); + } + + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + + /* A colon is used in expansion-statement. */ + parser->colon_corrects_to_scope_p = false; + + /* Parse the declaration. */ + tree range_decl; + cp_parser_simple_declaration (parser, + /*function_definition_allowed_p=*/false, + &range_decl); + if (range_decl == NULL_TREE) + range_decl = error_mark_node; + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + cp_parser_require (parser, CPP_COLON, RT_COLON); + + auto_vec <cxx_binding *> bindings; + auto_vec <tree> names; + cp_decomp decomp_d; + + /* Get the range declaration momentarily out of the way so that + the range expression doesn't clash with it. */ + cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings, + names); + + tree expansion_init; + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + expansion_init = cp_parser_braced_list (parser); + if (TREE_CODE (expansion_init) == CONSTRUCTOR + && CONSTRUCTOR_IS_DESIGNATED_INIT (expansion_init)) + error_at (EXPR_LOC_OR_LOC (expansion_init, token->location), + "designators in %<template for%> initializer"); + } + else + expansion_init = cp_parser_expression (parser); + + /* Put the range declaration(s) back into scope. */ + for (unsigned int i = 0; i < names.length (); i++) + { + cxx_binding *binding = bindings[i]; + binding->previous = IDENTIFIER_BINDING (names[i]); + IDENTIFIER_BINDING (names[i]) = binding; + } + + /* Look for the `)'. */ + parens.require_close (parser); + + if (processing_template_decl + && check_for_bare_parameter_packs (expansion_init)) + expansion_init = error_mark_node; + + if (expansion_init != error_mark_node + && !type_dependent_expression_p (expansion_init) + && TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE + && !BRACE_ENCLOSED_INITIALIZER_P (expansion_init)) + do_range_for_auto_deduction (range_decl, expansion_init, decomp, + true); + + bool outside_of_template = !processing_template_decl; + if (outside_of_template) + { + ++processing_template_decl; + current_template_parms + = tree_cons (size_int (current_template_depth + 1), + make_tree_vec (0), current_template_parms); + } + in_expansion_stmt = true; + + tree r = build_stmt (token->location, TEMPLATE_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + + current_binding_level->this_entity = r; + TEMPLATE_FOR_INIT_STMT (r) = init; + TEMPLATE_FOR_SCOPE (r) = scope; + if (!outside_of_template) + TEMPLATE_FOR_INIT_STMT (r) = pop_stmt_list (TEMPLATE_FOR_INIT_STMT (r)); + TEMPLATE_FOR_DECL (r) = range_decl; + TEMPLATE_FOR_EXPR (r) = expansion_init; + TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block); + + /* Parse the body of the expansion-statement. */ + parser->in_statement = IN_EXPANSION_STMT; + bool prev = note_iteration_stmt_body_start (); + cp_parser_already_scoped_statement (parser, if_p, guard_tinfo); + note_iteration_stmt_body_end (prev); + parser->in_statement = in_statement; + in_expansion_stmt = save_in_expansion_stmt; + + TEMPLATE_FOR_BODY (r) = do_poplevel (TEMPLATE_FOR_BODY (r)); + + if (outside_of_template) + { + current_template_parms = TREE_CHAIN (current_template_parms); + --processing_template_decl; + } + + if (VAR_P (range_decl) && DECL_DECLARED_CONSTINIT_P (range_decl)) + error_at (DECL_SOURCE_LOCATION (range_decl), + "for-range-declaration cannot be 'constinit'"); + + if (decomp) + { + tree v = make_tree_vec (decomp->count + 1); + TREE_VEC_ELT (v, 0) = TEMPLATE_FOR_DECL (r); + tree d = decomp->decl; + for (unsigned i = 0; i < decomp->count; ++i, d = DECL_CHAIN (d)) + TREE_VEC_ELT (v, decomp->count - i) = d; + TEMPLATE_FOR_DECL (r) = v; + } + + if (processing_template_decl) + add_stmt (r); + else + finish_expansion_stmt (r, NULL_TREE, tf_warning_or_error, NULL_TREE); + + add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (r))); + TEMPLATE_FOR_SCOPE (r) = NULL_TREE; + + return r; +} + /* Parse a jump-statement. jump-statement: @@ -15292,7 +15771,8 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) break; default: gcc_assert ((in_statement & IN_SWITCH_STMT) - || in_statement == IN_ITERATION_STMT); + || in_statement == IN_ITERATION_STMT + || in_statement == IN_EXPANSION_STMT); statement = finish_break_stmt (); if (in_statement == IN_ITERATION_STMT) break_maybe_infinite_loop (); @@ -15315,6 +15795,7 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) break; /* Fall through. */ case IN_ITERATION_STMT: + case IN_EXPANSION_STMT: case IN_OMP_FOR: statement = finish_continue_stmt (); break; @@ -15389,11 +15870,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 +16267,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; } } @@ -15972,15 +16460,16 @@ cp_parser_declaration_seq_opt (cp_parser* parser) static void cp_parser_declaration (cp_parser* parser, tree prefix_attrs) { - int saved_pedantic; + int saved_pedantic, saved_long_long; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Parse the qualified declaration. */ cp_parser_declaration (parser, prefix_attrs); /* Restore the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -16222,6 +16711,56 @@ cp_parser_toplevel_declaration (cp_parser* parser) cp_parser_declaration (parser, NULL_TREE); } +/* Build an empty string for static_assert. */ + +static tree +build_empty_string () +{ + tree message = build_string (1, ""); + TREE_TYPE (message) = char_array_type_node; + fix_string_type (message); + return message; +} + +/* Return true iff the next tokens start a C++26 consteval block. */ + +static bool +cp_parser_next_tokens_are_consteval_block_p (cp_parser *parser) +{ + return (cxx_dialect >= cxx26 + && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE)); +} + +/* Parse a consteval-block-declaration. + + consteval-block-declaration: + consteval compound-statement + + If MEMBER_P, this consteval block is a member declaration. */ + +static void +cp_parser_consteval_block (cp_parser *parser, bool member_p) +{ + const location_t loc = cp_lexer_peek_token (parser->lexer)->location; + /* Consume the 'consteval'. */ + cp_lexer_consume_token (parser->lexer); + + /* We know the next token is '{'. Let cp_parser_lambda_body handle it. */ + cp_expr lam = cp_parser_lambda_expression (parser, + /*consteval_block_p=*/true); + if (!cp_parser_error_occurred (parser)) + { + releasing_vec args; + tree call = finish_call_expr (lam, &args, + /*disallow_virtual=*/false, + /*koenig_p=*/false, + tf_warning_or_error); + finish_static_assert (call, build_empty_string (), loc, member_p, + /*show_expr_p=*/false, /*consteval_block_p=*/true); + } +} + /* Parse a block-declaration. block-declaration: @@ -16229,18 +16768,18 @@ cp_parser_toplevel_declaration (cp_parser* parser) asm-definition namespace-alias-definition using-declaration + using-enum-declaration using-directive + static_assert-declaration + consteval-block-declaration + alias-declaration + opaque-enum-declaration GNU Extension: block-declaration: __extension__ block-declaration - C++0x Extension: - - block-declaration: - static_assert-declaration - If STATEMENT_P is TRUE, then this block-declaration is occurring as part of a declaration-statement. */ @@ -16248,15 +16787,16 @@ static void cp_parser_block_declaration (cp_parser *parser, bool statement_p) { - int saved_pedantic; + int saved_pedantic, saved_long_long; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Parse the qualified declaration. */ cp_parser_block_declaration (parser, statement_p); /* Restore the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -16317,6 +16857,8 @@ cp_parser_block_declaration (cp_parser *parser, /* If the next token is `static_assert' we have a static assertion. */ else if (token1->keyword == RID_STATIC_ASSERT) cp_parser_static_assert (parser, /*member_p=*/false); + else if (cp_parser_next_tokens_are_consteval_block_p (parser)) + cp_parser_consteval_block (parser, /*member_p=*/false); else { size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1); @@ -16688,7 +17230,7 @@ cp_parser_simple_declaration (cp_parser* parser, } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. - decl-specifier-seq ref-qualifier [opt] [ identifier-list ] + decl-specifier-seq ref-qualifier [opt] [ sb-identifier-list ] initializer ; */ static tree @@ -16701,21 +17243,45 @@ cp_parser_decomposition_declaration (cp_parser *parser, location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE); - /* Parse the identifier-list. */ + /* Parse the sb-identifier-list. */ auto_vec<cp_expr, 10> v; bool attr_diagnosed = false; int first_attr = -1; + int pack = -1; unsigned int cnt = 0; if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) while (true) { + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + location_t elloc = cp_lexer_peek_token (parser->lexer)->location; + if (!processing_template_decl) + error_at (elloc, "structured binding pack outside of template"); + else if (pack != -1) + error_at (elloc, + "multiple packs in structured binding declaration"); + else + { + if (keyword == RID_MAX + && cxx_dialect >= cxx17 + && cxx_dialect < cxx26) + pedwarn (elloc, OPT_Wc__26_extensions, + "structured binding packs only available with " + "%<-std=c++2c%> or %<-std=gnu++2c%>"); + pack = cnt; + } + cp_lexer_consume_token (parser->lexer); + } cp_expr e = cp_parser_identifier (parser); if (e.get_value () == error_mark_node) break; tree attr = NULL_TREE; if (cp_next_tokens_can_be_std_attribute_p (parser)) { - if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed) + if (keyword == RID_MAX + && cxx_dialect >= cxx17 + && cxx_dialect < cxx26 + && !attr_diagnosed) { pedwarn (cp_lexer_peek_token (parser->lexer)->location, OPT_Wc__26_extensions, @@ -16776,7 +17342,7 @@ cp_parser_decomposition_declaration (cp_parser *parser, &pushed_scope); tree orig_decl = decl; - unsigned int i; + unsigned int i, j; cp_expr e; cp_decl_specifier_seq decl_specs; clear_decl_specs (&decl_specs); @@ -16784,6 +17350,7 @@ cp_parser_decomposition_declaration (cp_parser *parser, if (decl_specifiers->storage_class == sc_static) decl_specs.storage_class = sc_static; tree prev = decl; + j = 0; FOR_EACH_VEC_ELT (v, i, e) { if (i == 0) @@ -16810,9 +17377,31 @@ cp_parser_decomposition_declaration (cp_parser *parser, decl = error_mark_node; } else - prev = decl2; + { + prev = decl2; + if (decl != error_mark_node) + { + DECL_DECLARED_CONSTEXPR_P (decl2) + = DECL_DECLARED_CONSTEXPR_P (decl); + DECL_DECLARED_CONSTINIT_P (decl2) + = DECL_DECLARED_CONSTINIT_P (decl); + } + if (j == (unsigned) pack) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = decl2; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + tree type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = decl2; + TREE_TYPE (decl2) = type; + } + } if (elt_pushed_scope) pop_scope (elt_pushed_scope); + ++j; } if (v.is_empty ()) @@ -16859,6 +17448,15 @@ cp_parser_decomposition_declaration (cp_parser *parser, /* Ensure DECL_VALUE_EXPR is created for all the decls but the underlying DECL. */ cp_finish_decomp (decl, &decomp); + if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread)) + pedwarn (decl_specifiers->locations[ds_thread], + 0, "for-range-declaration cannot be %qs", + decl_specifiers->gnu_thread_keyword_p + ? "__thread" : "thread_local"); + else if (decl_specifiers->storage_class == sc_static) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "static"); } if (pushed_scope) @@ -17607,9 +18205,7 @@ cp_parser_static_assert (cp_parser *parser, bool member_p) "only available with %<-std=c++17%> or %<-std=gnu++17%>"); /* Eat the ')' */ cp_lexer_consume_token (parser->lexer); - message = build_string (1, ""); - TREE_TYPE (message) = char_array_type_node; - fix_string_type (message); + message = build_empty_string (); } else { @@ -20952,9 +21548,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, "only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); } - else if (parser->in_template_argument_list_p) - error_at (token->location, - "use of %<auto%> in template argument"); else if (!flag_concepts) pedwarn (token->location, OPT_Wc__20_extensions, "use of %<auto%> in parameter declaration " @@ -20964,6 +21557,11 @@ cp_parser_simple_type_specifier (cp_parser* parser, "use of %<auto%> in parameter declaration " "only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); + + if (parser->in_template_argument_list_p) + permerror_opt (token->location, + OPT_Wabbreviated_auto_in_template_arg, + "use of %<auto%> in template argument"); } else type = make_auto (); @@ -21092,7 +21690,9 @@ cp_parser_simple_type_specifier (cp_parser* parser, /*typename_keyword_p=*/false, /*check_dependency_p=*/true, /*type_p=*/false, - /*is_declaration=*/false) + /*is_declaration=*/false, + /*template_keyword_p=*/false, + global_p) != NULL_TREE); /* If we have seen a nested-name-specifier, and the next token is `template', then we are using the template-id production. */ @@ -21410,6 +22010,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc, error_at (loc, "cannot declare a parameter with %<decltype(auto)%>"); return error_mark_node; } + if (parser->in_template_argument_list_p) + permerror_opt (placeholder->location, + OPT_Wabbreviated_auto_in_template_arg, + "use of %<auto%> in template argument"); tree parm = build_constrained_parameter (con, proto, args); return synthesize_implicit_template_parm (parser, parm); } @@ -21938,7 +22542,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, bool template_p = (template_parm_lists_apply - && (cp_parser_next_token_starts_class_definition_p (parser) + && (cp_parser_nth_token_starts_class_definition_p (parser, 1) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); /* An unqualified name was used to reference this type, so there were no qualifying templates. */ @@ -24102,7 +24706,26 @@ cp_parser_init_declarator (cp_parser* parser, && token->type != CPP_SEMICOLON) { if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node) - range_for_decl_p = true; + { + range_for_decl_p = true; + if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread)) + pedwarn (decl_specifiers->locations[ds_thread], + 0, "for-range-declaration cannot be %qs", + decl_specifiers->gnu_thread_keyword_p + ? "__thread" : "thread_local"); + else if (decl_specifiers->storage_class == sc_static) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "static"); + else if (decl_specifiers->storage_class == sc_extern) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "extern"); + else if (decl_specifiers->storage_class == sc_register) + pedwarn (decl_specifiers->locations[ds_storage_class], + 0, "for-range-declaration cannot be %qs", + "register"); + } else { if (!maybe_range_for_decl) @@ -26893,6 +27516,10 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/) location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; auto oas = make_temp_override (parser->omp_array_section_p, false); + /* Within a brace-enclosed initializer list, a `>' token is always the + greater-than operator. */ + auto gto = make_temp_override (parser->greater_than_is_operator_p, true); + /* Consume the `{' token. */ matching_braces braces; bool found_opening_brace = braces.require_open (parser); @@ -27956,6 +28583,98 @@ cp_parser_class_specifier (cp_parser* parser) return type; } +/* Parse an (optional) class-property-specifier-seq. + + class-property-specifier-seq: + class-property-specifier class-property-specifier-seq [opt] + + class-property-specifier: + final + trivially_relocatable_if_eligible (C++26) + replaceable_if_eligible (C++26) + + Returns a bitmask representing the class-property-specifiers. */ + +static cp_virt_specifiers +cp_parser_class_property_specifier_seq_opt (cp_parser *parser) +{ + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; + + while (true) + { + cp_token *token; + cp_virt_specifiers virt_specifier; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's a class-property-specifier. */ + if (token->type != CPP_NAME) + break; + if (id_equal (token->u.value, "final")) + { + /* For C++98, quietly ignore final in e.g. + struct S final = 24; */ + if (cxx_dialect == cxx98 + && virt_specifiers == VIRT_SPEC_UNSPECIFIED + && !cp_parser_nth_token_starts_class_definition_p (parser, 2) + && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + break; + maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS); + virt_specifier = VIRT_SPEC_FINAL; + } + else if (id_equal (token->u.value, "__final")) + virt_specifier = VIRT_SPEC_FINAL; + else if (id_equal (token->u.value, "trivially_relocatable_if_eligible")) + { + if (cxx_dialect < cxx26) + { + /* Warn about the C++26 conditional keyword (but don't parse + it). */ + warning_at (token->location, OPT_Wc__26_compat, + "identifier %qE is a conditional keyword in C++26", + token->u.value); + break; + } + virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE; + } + else if (id_equal (token->u.value, + "__trivially_relocatable_if_eligible")) + virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE; + else if (id_equal (token->u.value, "replaceable_if_eligible")) + { + if (cxx_dialect < cxx26) + { + /* Warn about the C++26 conditional keyword (but don't parse + it). */ + warning_at (token->location, OPT_Wc__26_compat, + "identifier %qE is a conditional keyword in C++26", + token->u.value); + break; + } + virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE; + } + else if (id_equal (token->u.value, + "__replaceable_if_eligible")) + virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE; + else + break; + + if (virt_specifiers & virt_specifier) + { + gcc_rich_location richloc (token->location); + richloc.add_fixit_remove (); + error_at (&richloc, "duplicate %qD specifier", token->u.value); + cp_lexer_purge_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + virt_specifiers |= virt_specifier; + } + } + return virt_specifiers; +} + /* Parse a class-head. class-head: @@ -28146,18 +28865,16 @@ cp_parser_class_head (cp_parser* parser, pop_deferring_access_checks (); if (id) - { - cp_parser_check_for_invalid_template_id (parser, id, - class_key, - type_start_token->location); - } - virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); + cp_parser_check_for_invalid_template_id (parser, id, + class_key, + type_start_token->location); + virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser); /* If it's not a `:' or a `{' then we can't really be looking at a class-head, since a class-head only appears as part of a class-specifier. We have to detect this situation before calling xref_tag, since that has irreversible side-effects. */ - if (!cp_parser_next_token_starts_class_definition_p (parser)) + if (!cp_parser_nth_token_starts_class_definition_p (parser, 1)) { cp_parser_error (parser, "expected %<{%> or %<:%>"); type = error_mark_node; @@ -28167,13 +28884,6 @@ cp_parser_class_head (cp_parser* parser, /* At this point, we're going ahead with the class-specifier, even if some other problem occurs. */ cp_parser_commit_to_tentative_parse (parser); - if (virt_specifiers & VIRT_SPEC_OVERRIDE) - { - cp_parser_error (parser, - "cannot specify %<override%> for a class"); - type = error_mark_node; - goto out; - } /* Issue the error about the overly-qualified name now. */ if (qualified_p) { @@ -28501,6 +29211,16 @@ cp_parser_class_head (cp_parser* parser, DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location; if (type && (virt_specifiers & VIRT_SPEC_FINAL)) CLASSTYPE_FINAL (type) = 1; + if (type && (virt_specifiers & VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE)) + { + gcc_assert (!CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (type)); + CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (type) = 1; + } + if (type && (virt_specifiers & VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE)) + { + gcc_assert (!CLASSTYPE_REPLACEABLE_COMPUTED (type)); + CLASSTYPE_REPLACEABLE_BIT (type) = 1; + } out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; return type; @@ -28619,12 +29339,20 @@ cp_parser_member_specification_opt (cp_parser* parser) /* Parse a member-declaration. member-declaration: - decl-specifier-seq [opt] member-declarator-list [opt] ; - function-definition ; [opt] - :: [opt] nested-name-specifier template [opt] unqualified-id ; + attribute-specifier-seq [opt] decl-specifier-seq [opt] + member-declarator-list [opt] ; + function-definition + friend-type-declaration using-declaration + using-enum-declaration + static_assert-declaration + consteval-block-declaration template-declaration + explicit-specialization + deduction-guide alias-declaration + opaque-enum-declaration + empty-declaration member-declarator-list: member-declarator @@ -28643,12 +29371,7 @@ cp_parser_member_specification_opt (cp_parser* parser) member-declarator: declarator attributes [opt] pure-specifier [opt] declarator attributes [opt] constant-initializer [opt] - identifier [opt] attributes [opt] : constant-expression - - C++0x Extensions: - - member-declaration: - static_assert-declaration */ + identifier [opt] attributes [opt] : constant-expression */ static void cp_parser_member_declaration (cp_parser* parser) @@ -28661,16 +29384,17 @@ cp_parser_member_declaration (cp_parser* parser) cp_token *token = NULL; cp_token *decl_spec_token_start = NULL; cp_token *initializer_token_start = NULL; - int saved_pedantic; + int saved_pedantic, saved_long_long; bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; /* Check for the `__extension__' keyword. */ - if (cp_parser_extension_opt (parser, &saved_pedantic)) + if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long)) { /* Recurse. */ cp_parser_member_declaration (parser); /* Restore the old value of the PEDANTIC flag. */ pedantic = saved_pedantic; + warn_long_long = saved_long_long; return; } @@ -28747,6 +29471,12 @@ cp_parser_member_declaration (cp_parser* parser) return; } + if (cp_parser_next_tokens_are_consteval_block_p (parser)) + { + cp_parser_consteval_block (parser, /*member_p=*/true); + return; + } + parser->colon_corrects_to_scope_p = false; cp_omp_declare_simd_data odsd; @@ -30372,6 +31102,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); @@ -31809,13 +32542,16 @@ cp_parser_skip_attributes_opt (cp_parser *parser, size_t n) present, and FALSE otherwise. *SAVED_PEDANTIC is set to the current value of the PEDANTIC flag, regardless of whether or not the `__extension__' keyword is present. The caller is responsible - for restoring the value of the PEDANTIC flag. */ + for restoring the value of the PEDANTIC flag. Similarly *SAVED_LONG_LONG + for warn_long_long flag. */ static bool -cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic) +cp_parser_extension_opt (cp_parser *parser, int *saved_pedantic, + int *saved_long_long) { /* Save the old value of the PEDANTIC flag. */ *saved_pedantic = pedantic; + *saved_long_long = warn_long_long; if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION)) { @@ -31824,6 +32560,8 @@ cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic) /* We're not being pedantic while the `__extension__' keyword is in effect. */ pedantic = 0; + /* And we don't want -Wlong-long warning. */ + warn_long_long = 0; return true; } @@ -32671,9 +33409,12 @@ cp_parser_compound_requirement (cp_parser *parser) } } else - /* P1452R2 removed the trailing-return-type option. */ - error_at (type_loc, - "return-type-requirement is not a type-constraint"); + { + /* P1452R2 removed the trailing-return-type option. */ + error_at (type_loc, + "return-type-requirement is not a type-constraint"); + type = NULL_TREE; + } } location_t loc = make_location (expr_token->location, @@ -33498,7 +34239,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, && cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID) { auto_diagnostic_group d; - if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING, + if (emit_diagnostic ((cxx_dialect >= cxx20 + ? diagnostics::kind::pedwarn + : diagnostics::kind::warning), input_location, OPT_Wtemplate_id_cdtor, "template-id not allowed for constructor in C++20")) inform (input_location, "remove the %qs", "< >"); @@ -33634,6 +34377,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 +34398,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)) @@ -35534,15 +36282,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token) || token->keyword == RID_RETURN); } -/* Returns TRUE iff the next token is the ":" or "{" beginning a class +/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class definition. */ static bool -cp_parser_next_token_starts_class_definition_p (cp_parser *parser) +cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n) { cp_token *token; - token = cp_lexer_peek_token (parser->lexer); + token = cp_lexer_peek_nth_token (parser->lexer, n); return (token->type == CPP_OPEN_BRACE || (token->type == CPP_COLON && !parser->colon_doesnt_start_class_def_p)); @@ -35822,7 +36570,9 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, return; bool seen_as_union = TREE_CODE (type) == UNION_TYPE; - if (seen_as_union != (class_key == union_type)) + if (class_key != typename_type + && TREE_CODE (type) != TYPENAME_TYPE + && seen_as_union != (class_key == union_type)) { auto_diagnostic_group d; if (permerror (input_location, "%qs tag used in naming %q#T", @@ -36433,7 +37183,11 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) case CPP_CLOSE_SQUARE: if (depth == 0 /* Handle correctly int n = sizeof ... ( p ); */ - && token->type != CPP_ELLIPSIS) + && (token->type != CPP_ELLIPSIS + /* For int n = 42 ...) handle ... as variadic arguments. */ + || (!nsdmi + && cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)))) done = true; /* Update DEPTH, if necessary. */ else if (token->type == CPP_CLOSE_PAREN @@ -36596,7 +37350,7 @@ static void cp_parser_abort_tentative_parse (cp_parser* parser) { gcc_assert (parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED - || errorcount > 0); + || seen_error ()); cp_parser_simulate_error (parser); /* Now, pretend that we want to see if the construct was successfully parsed. */ @@ -42323,8 +43077,11 @@ cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc) to ( variable-list ) OpenMP 5.1: - from ( [present :] variable-list ) - to ( [present :] variable-list ) */ + from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + + motion-modifier: + present | iterator (iterators-definition) */ static tree cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, @@ -42333,23 +43090,113 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - bool present = false; - cp_token *token = cp_lexer_peek_token (parser->lexer); + int pos = 1; + int colon_pos = 0; + int iterator_length = 0; - if (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->u.value), "present") == 0 - && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME) { - present = true; - cp_lexer_consume_token (parser->lexer); - cp_lexer_consume_token (parser->lexer); + const char *identifier = + IDENTIFIER_POINTER (cp_lexer_peek_nth_token (parser->lexer, + pos)->u.value); + if (cp_lexer_nth_token_is (parser->lexer, pos + 1, CPP_OPEN_PAREN)) + { + int n = cp_parser_skip_balanced_tokens (parser, pos + 1); + if (n != pos + 1) + { + if (strcmp (identifier, "iterator") == 0) + iterator_length = n - pos; + pos = n - 1; + } + } + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + pos += 2; + else + pos++; + if (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_COLON) + { + colon_pos = pos; + break; + } } + bool present = false; + tree iterators = NULL_TREE; + + for (int pos = 1; pos < colon_pos; ++pos) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_COMMA) + { + cp_lexer_consume_token (parser->lexer); + continue; + } + const char *p = IDENTIFIER_POINTER (token->u.value); + if (strcmp ("present", p) == 0) + { + if (present) + { + cp_parser_error (parser, "too many %<present%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + present = true; + cp_lexer_consume_token (parser->lexer); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + cp_parser_error (parser, "too many %<iterator%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + + else + { + error_at (token->location, + "%qs clause with modifier other than %<iterator%> " + "or %<present%>", + kind == OMP_CLAUSE_TO ? "to" : "from"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + } + + if (colon_pos) + cp_parser_require (parser, CPP_COLON, RT_COLON); + tree nl = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, true); if (present) for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MOTION_PRESENT (c) = 1; + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + if (iterators) + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ITERATORS (c) = iterators; + return nl; } @@ -42370,36 +43217,60 @@ 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; int pos = 1; int map_kind_pos = 0; - while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME - || cp_lexer_peek_nth_token (parser->lexer, pos)->keyword == RID_DELETE) + int iterator_length = 0; + for (;;) { - if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON) + cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, pos); + if (!(tok->type == CPP_NAME || tok->keyword == RID_DELETE)) + break; + + cp_token *next_tok = cp_lexer_peek_nth_token (parser->lexer, pos + 1); + if (tok->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (tok->u.value), "iterator") == 0 + && next_tok->type == CPP_OPEN_PAREN) + { + int n = cp_parser_skip_balanced_tokens (parser, pos + 1); + if (n != pos + 1) + { + iterator_length = n - pos; + pos = n - 1; + next_tok = cp_lexer_peek_nth_token (parser->lexer, n); + } + } + + if (next_tok->type == CPP_COLON) { map_kind_pos = pos; break; } - if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + if (next_tok->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; + tree iterators = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { cp_token *tok = cp_lexer_peek_token (parser->lexer); @@ -42422,6 +43293,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 +43307,92 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) return list; } close_modifier = true; + cp_lexer_consume_token (parser->lexer); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + cp_parser_error (parser, "too many %<iterator%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + 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 +43406,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%>, " + "%<iterator%>, %<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 +43474,40 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) NULL, true); finish_scope (); + tree last_new = NULL_TREE; + + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_SET_MAP_KIND (c, kind); + { + OMP_CLAUSE_SET_MAP_KIND (c, kind); + OMP_CLAUSE_ITERATORS (c) = iterators; + 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 +44835,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: @@ -45750,8 +46741,16 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; decomp->decl = decl; } + else if (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))) + { + d = TREE_VEC_ELT (v, 0); + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + decomp->decl = decl; + } } - do_range_for_auto_deduction (d, init, decomp); + do_range_for_auto_deduction (d, init, decomp, false); } cond = global_namespace; incr = NULL_TREE; @@ -45807,8 +46806,8 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, range_temp_decl = range_temp; range_temp = convert_from_reference (range_temp); } - iter_type = cp_parser_perform_range_for_lookup (range_temp, - &begin_expr, &end_expr); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr); } tree end_iter_type = iter_type; @@ -45873,6 +46872,15 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl, decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; decomp->decl = d; } + else if (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))) + { + tree d = orig_decl; + orig_decl = TREE_VEC_ELT (v, 0); + decomp = &decomp_d; + decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1; + decomp->decl = d; + } } tree auto_node = type_uses_auto (TREE_TYPE (orig_decl)); @@ -48851,6 +49859,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 +50555,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 +50841,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; @@ -50620,41 +51644,41 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, append_args_tree); } } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)); + if (variant != error_mark_node && !has_match) + { + cp_parser_error (parser, "expected %<match%> clause"); + variant = error_mark_node; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); - if ((ctx != error_mark_node && variant != error_mark_node) - && (has_adjust_args || append_args_tree)) + /* At this point, we have completed parsing of the pragma, now it's + on to error checking. */ + if (variant == error_mark_node || ctx == error_mark_node) + /* Previously diagnosed error. */ + return attrs; + + if (has_adjust_args || append_args_tree) { - if (!has_match) + if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, + OMP_TRAIT_CONSTRUCT_DISPATCH)) { error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause requires a %<match%> clause", + "an %qs clause can only be specified if the %<dispatch%> " + "selector of the construct selector set appears " + "in the %<match%> clause", has_adjust_args ? "adjust_args" : "append_args"); + return attrs; } - else - { - gcc_assert (TREE_PURPOSE (attrs) - == get_identifier ("omp declare variant base")); - gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant); - ctx = TREE_VALUE (TREE_VALUE (attrs)); - if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, - OMP_TRAIT_CONSTRUCT_DISPATCH)) - error_at (has_adjust_args ? adjust_args_loc : append_args_loc, - "an %qs clause can only be specified if the %<dispatch%> " - "selector of the construct selector set appears " - "in the %<match%> clause", - has_adjust_args ? "adjust_args" : "append_args"); - // We might not have a DECL for the variant yet. So we store the - // need_device_ptr list in the base function attribute, after loc - // nodes. - tree t = build_tree_list (need_device_ptr_list, - NULL_TREE /* need_device_addr */); - TREE_CHAIN (t) = append_args_tree; - TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs), - build_tree_list ( NULL_TREE, t)); - } + // We might not have a DECL for the variant yet. So we store the + // need_device_ptr list in the base function attribute, after loc + // nodes. + tree t = build_tree_list (need_device_ptr_list, + NULL_TREE /* need_device_addr */); + TREE_CHAIN (t) = append_args_tree; + TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs), + build_tree_list (NULL_TREE, t)); } - cp_parser_skip_to_pragma_eol (parser, pragma_tok); return attrs; } @@ -51404,7 +52428,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 +52437,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 +52511,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 +52583,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 +52598,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 +52729,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 +53149,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 +53362,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 +53381,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; } @@ -52548,11 +53741,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok, if (msg == NULL) msg = _("<message unknown at compile time>"); } + const enum diagnostics::kind diag_kind = (severity_fatal + ? diagnostics::kind::error + : diagnostics::kind::warning); if (msg) - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered: %s", msg); else - emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + emit_diagnostic (diag_kind, loc, 0, "%<pragma omp error%> encountered"); return false; } diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index f9ed801..3a17be9 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -328,14 +328,16 @@ struct GTY(()) cp_parser { /* Set to IN_ITERATION_STMT if parsing an iteration-statement, to IN_OMP_BLOCK if parsing OpenMP structured block and - IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement, + IN_OMP_FOR if parsing OpenMP loop, IN_EXPANSION_STMT if parsing an + expansion-statement. If parsing a switch statement, this is bitwise ORed with IN_SWITCH_STMT, unless parsing an iteration-statement, OpenMP block or loop within that switch. */ #define IN_SWITCH_STMT 1 #define IN_ITERATION_STMT 2 #define IN_OMP_BLOCK 4 #define IN_OMP_FOR 8 -#define IN_IF_STMT 16 +#define IN_IF_STMT 16 +#define IN_EXPANSION_STMT 32 unsigned char in_statement; /* TRUE if we are presently parsing the body of a switch statement. diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 63c2ec0..9b79267 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); @@ -6953,14 +6952,22 @@ convert_nontype_argument_function (tree type, tree expr, { auto_diagnostic_group d; location_t loc = cp_expr_loc_or_input_loc (expr); - error_at (loc, "%qE is not a valid template argument for type %qT", - expr, type); - if (TYPE_PTR_P (type)) - inform (loc, "it must be the address of a function " - "with external linkage"); + tree c; + if (cxx_dialect >= cxx17 + && (c = cxx_constant_value (fn), + c == error_mark_node)) + ; else - inform (loc, "it must be the name of a function with " - "external linkage"); + { + error_at (loc, "%qE is not a valid template argument for " + "type %qT", expr, type); + if (TYPE_PTR_P (type)) + inform (loc, "it must be the address of a function " + "with external linkage"); + else + inform (loc, "it must be the name of a function with " + "external linkage"); + } } return NULL_TREE; } @@ -7403,22 +7410,22 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) /* Null pointer values are OK in C++11. */; else { - if (VAR_P (expr)) - { - if (complain & tf_error) - error ("%qD is not a valid template argument " - "because %qD is a variable, not the address of " - "a variable", expr, expr); - return true; - } + tree c; + if (!(complain & tf_error)) + ; + else if (cxx_dialect >= cxx17 + && (c = cxx_constant_value (expr), + c == error_mark_node)) + ; + else if (VAR_P (expr)) + error ("%qD is not a valid template argument " + "because %qD is a variable, not the address of " + "a variable", expr, expr); else - { - if (complain & tf_error) - error ("%qE is not a valid template argument for %qT " - "because it is not the address of a variable", - expr, type); - return true; - } + error ("%qE is not a valid template argument for %qT " + "because it is not the address of a variable", + expr, type); + return true; } } return false; @@ -7492,8 +7499,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 +10059,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 +10091,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))) { @@ -11373,6 +11393,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; @@ -11418,12 +11439,50 @@ 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 || TREE_CODE (tldcl) == TEMPLATE_FOR_STMT) + && !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 (TREE_CODE (tldcl) == TEMPLATE_FOR_STMT) + pp_printf (&pp, "I template for"); + else 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; @@ -11468,10 +11527,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. */ @@ -11487,9 +11563,43 @@ 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 (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT) + pp_printf (&pp, "RI template for"); + else 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 ()) { @@ -11772,6 +11882,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); @@ -12425,6 +12539,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); @@ -12596,7 +12712,17 @@ instantiate_class_template (tree type) determine_visibility (TYPE_MAIN_DECL (type)); } if (CLASS_TYPE_P (type)) - CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern); + { + CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern); + CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (type) + = CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (pattern); + CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (type) + = CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (pattern); + CLASSTYPE_REPLACEABLE_BIT (type) + = CLASSTYPE_REPLACEABLE_BIT (pattern); + CLASSTYPE_REPLACEABLE_COMPUTED (type) + = CLASSTYPE_REPLACEABLE_COMPUTED (pattern); + } pbinfo = TYPE_BINFO (pattern); @@ -13748,6 +13874,8 @@ 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); @@ -13858,9 +13986,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, else if (is_capture_proxy (parm_pack)) { arg_pack = retrieve_local_specialization (parm_pack); + if (DECL_DECOMPOSITION_P (arg_pack)) + { + orig_arg = arg_pack; + goto expand_sb_pack; + } if (DECL_PACK_P (arg_pack)) arg_pack = NULL_TREE; } + else if (DECL_DECOMPOSITION_P (parm_pack)) + { + orig_arg = retrieve_local_specialization (parm_pack); + expand_sb_pack: + gcc_assert (DECL_DECOMPOSITION_P (orig_arg)); + if (TREE_TYPE (orig_arg) == error_mark_node) + return error_mark_node; + gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg)); + arg_pack = DECL_VALUE_EXPR (orig_arg); + tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2); + if (TREE_VEC_LENGTH (vec)) + memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2), + TREE_VEC_LENGTH (vec) * sizeof (tree)); + arg_pack = make_node (NONTYPE_ARGUMENT_PACK); + ARGUMENT_PACK_ARGS (arg_pack) = vec; + } else { int idx; @@ -13873,7 +14022,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, arg_pack = NULL_TREE; } - orig_arg = arg_pack; + if (orig_arg == NULL_TREE) + orig_arg = arg_pack; if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT) arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack); @@ -13888,8 +14038,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, if (arg_pack) { - int my_len = - TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); + int my_len + = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); /* Don't bother trying to do a partial substitution with incomplete packs; we'll try again after deduction. */ @@ -14053,8 +14203,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, /* Update the corresponding argument. */ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) - TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) = - TREE_TYPE (pack); + TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) + = TREE_TYPE (pack); else TREE_VEC_ELT (args, idx) = TREE_TYPE (pack); } @@ -14801,6 +14951,9 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, argvec = NULL_TREE; } + /* Make sure tsubst_decl substitutes all the parameters. */ + cp_evaluated ev; + tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype) : NULL_TREE); tree ctx = closure ? closure : DECL_CONTEXT (t); @@ -14885,6 +15038,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)) @@ -15457,6 +15612,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); @@ -15494,8 +15652,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; @@ -15785,7 +15948,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, tsubst_flags_t tcomplain = complain; if (VAR_P (t)) tcomplain |= tf_tst_ok; - type = tsubst (type, args, tcomplain, in_decl); + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + type = NULL_TREE; + else + type = tsubst (type, args, tcomplain, in_decl); /* Substituting the type might have recursively instantiated this same alias (c++/86171). */ if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl) @@ -15802,6 +15968,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, { DECL_INITIALIZED_P (r) = 0; DECL_TEMPLATE_INSTANTIATED (r) = 0; + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = r; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = r; + } if (TREE_CODE (type) == FUNCTION_TYPE) { /* It may seem that this case cannot occur, since: @@ -15891,7 +16068,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); } @@ -15943,6 +16123,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; @@ -17125,13 +17312,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; } - /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' vs 'union' - tags. TYPENAME_TYPE should probably remember the exact tag that - was written. */ + /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags. + TYPENAME_TYPE should probably remember the exact tag that + was written for -Wmismatched-tags. */ enum tag_types tag_type - = TYPENAME_IS_CLASS_P (t) ? class_type - : TYPENAME_IS_ENUM_P (t) ? enum_type - : typename_type; + = (TYPENAME_IS_CLASS_P (t) ? class_type + : TYPENAME_IS_UNION_P (t) ? union_type + : TYPENAME_IS_ENUM_P (t) ? enum_type + : typename_type); tsubst_flags_t tcomplain = complain | tf_keep_type_decl; tcomplain |= tst_ok_flag | qualifying_scope_flag; f = make_typename_type (ctx, f, tag_type, tcomplain); @@ -17153,10 +17341,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else return error_mark_node; } - else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f)) + else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f)) + { + if (complain & tf_error) + error ("%qT resolves to %qT, which is not a non-union " + "class type", t, f); + else + return error_mark_node; + } + else if (TYPENAME_IS_UNION_P (t) && !UNION_TYPE_P (f)) { if (complain & tf_error) - error ("%qT resolves to %qT, which is not a class type", + error ("%qT resolves to %qT, which is not a union type", t, f); else return error_mark_node; @@ -17169,18 +17365,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); } @@ -17454,10 +17656,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; } @@ -17828,9 +18038,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, return decl; /* Handle OpenMP iterators. */ - if (TREE_CODE (decl) == TREE_LIST - && TREE_PURPOSE (decl) - && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (decl)) { tree ret; if (iterator_cache[0] == TREE_PURPOSE (decl)) @@ -18201,8 +18409,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)) @@ -18256,7 +18466,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: @@ -18264,12 +18476,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) @@ -18370,13 +18596,17 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); - if (TREE_CODE (v) == ARRAY_REF - && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + if ((TREE_CODE (v) == ARRAY_REF + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + || (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))) { + v = (TREE_CODE (v) == ARRAY_REF + ? TREE_OPERAND (v, 0) : TREE_VEC_ELT (v, 0)); cp_decomp decomp_d = { NULL_TREE, 0 }; - tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain); + tree d = tsubst_decl (v, args, complain); maybe_push_decl (d); - d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain, + d = tsubst_decomp_names (d, v, args, complain, in_decl, &decomp_d); decomp = true; if (d == error_mark_node) @@ -19153,6 +19383,62 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_do_stmt (tmp, stmt, false, 0, false); break; + case TEMPLATE_FOR_STMT: + { + tree init; + stmt = build_stmt (EXPR_LOCATION (t), TEMPLATE_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + TEMPLATE_FOR_SCOPE (stmt) = begin_template_for_scope (&init); + TEMPLATE_FOR_INIT_STMT (stmt) = init; + RECUR (TEMPLATE_FOR_INIT_STMT (t)); + TEMPLATE_FOR_EXPR (stmt) = RECUR (TEMPLATE_FOR_EXPR (t)); + if (processing_template_decl) + { + tree orig_decl = TEMPLATE_FOR_DECL (t); + if (TREE_CODE (orig_decl) == TREE_VEC) + orig_decl = TREE_VEC_ELT (orig_decl, 0); + tree decl = tsubst (orig_decl, args, complain, in_decl); + maybe_push_decl (decl); + + cp_decomp decomp_d, *decomp = NULL; + if (DECL_DECOMPOSITION_P (decl)) + { + decomp = &decomp_d; + decl = tsubst_decomp_names (decl, orig_decl, args, + complain, in_decl, decomp); + if (decl != error_mark_node) + { + tree v = make_tree_vec (decomp->count + 1); + TREE_VEC_ELT (v, 0) = decl; + decl = decomp->decl; + for (unsigned i = 0; i < decomp->count; ++i) + { + TREE_VEC_ELT (v, decomp->count - i) = decl; + decl = DECL_CHAIN (decl); + } + decl = v; + } + } + TEMPLATE_FOR_DECL (stmt) = decl; + TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init); + add_stmt (stmt); + TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block); + bool prev = note_iteration_stmt_body_start (); + RECUR (TEMPLATE_FOR_BODY (t)); + note_iteration_stmt_body_end (prev); + TEMPLATE_FOR_BODY (stmt) + = do_poplevel (TEMPLATE_FOR_BODY (stmt)); + } + else + { + TEMPLATE_FOR_DECL (stmt) = TEMPLATE_FOR_DECL (t); + TEMPLATE_FOR_BODY (stmt) = TEMPLATE_FOR_BODY (t); + finish_expansion_stmt (stmt, args, complain, in_decl); + } + add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (stmt))); + } + break; + case IF_STMT: stmt = begin_if_stmt (); IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); @@ -19416,7 +19702,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_static_assert (condition, message, STATIC_ASSERT_SOURCE_LOCATION (t), - /*member_p=*/false, /*show_expr_p=*/true); + /*member_p=*/false, /*show_expr_p=*/true, + CONSTEVAL_BLOCK_P (t)); } break; @@ -19922,6 +20209,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; @@ -19965,7 +20268,14 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) { tree op0 = RECUR (TREE_OPERAND (t, 0)); tree cond = RECUR (MUST_NOT_THROW_COND (t)); - RETURN (build_must_not_throw_expr (op0, cond)); + stmt = build_must_not_throw_expr (op0, cond); + if (stmt && TREE_CODE (stmt) == MUST_NOT_THROW_EXPR) + { + MUST_NOT_THROW_NOEXCEPT_P (stmt) = MUST_NOT_THROW_NOEXCEPT_P (t); + MUST_NOT_THROW_THROW_P (stmt) = MUST_NOT_THROW_THROW_P (t); + MUST_NOT_THROW_CATCH_P (stmt) = MUST_NOT_THROW_CATCH_P (t); + } + RETURN (stmt); } case EXPR_PACK_EXPANSION: @@ -20280,6 +20590,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree fntype = static_fn_type (oldfn); + begin_scope (sk_lambda, NULL_TREE); + + /* Like in cp_parser_lambda_expression, we need to bring the captures + into the lambda scope. */ + tree ns = decl_namespace_context (type); + push_nested_namespace (ns); + push_nested_class (type); + tree dummy_fco = maybe_add_dummy_lambda_op (r); + pop_nested_class (); + pop_nested_namespace (ns); + push_capture_proxies (r, /*early_p=*/true); + tree saved_ctp = current_template_parms; if (oldtmpl) { @@ -20293,15 +20615,14 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) --processing_template_decl; } + /* We are about to create the real operator(), so get rid of the old one. */ + if (dummy_fco) + remove_dummy_lambda_op (dummy_fco, r); + if (fntype == error_mark_node) r = error_mark_node; else { - /* The body of a lambda-expression is not a subexpression of the - enclosing expression. Parms are to have DECL_CHAIN tsubsted, - which would be skipped if cp_unevaluated_operand. */ - cp_evaluated ev; - /* Fix the type of 'this'. For static and xobj member functions we use this to transport the lambda's closure type. It appears that in the regular case the @@ -20327,6 +20648,14 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* Let finish_function set this. */ DECL_DECLARED_CONSTEXPR_P (fn) = false; + /* The body of a lambda-expression is not a subexpression of the + enclosing expression. */ + cp_evaluated ev; + + /* Now we're done with the parameter-declaration-clause, and should + assume "const" unless "mutable" was present. */ + LAMBDA_EXPR_CONST_QUAL_P (r) = LAMBDA_EXPR_CONST_QUAL_P (t); + bool nested = cfun; if (nested) push_function_context (); @@ -20395,6 +20724,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } out: + pop_bindings_and_leave_scope (); finish_struct (type, /*attr*/NULL_TREE); insert_pending_capture_proxies (); @@ -20981,6 +21311,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))) @@ -20995,7 +21342,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ++c_inhibit_evaluation_warnings; /* We only want to compute the number of arguments. */ if (PACK_EXPANSION_P (op)) - expanded = tsubst_pack_expansion (op, args, complain, in_decl); + { + expanded = NULL_TREE; + if (DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op))) + { + tree d = PACK_EXPANSION_PATTERN (op); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + if (TREE_CODE (d) == TREE_VEC) + { + tree b = TREE_VEC_ELT (d, 0); + if (!type_dependent_expression_p_push (b)) + { + expanded = void_node; + len = TREE_VEC_LENGTH (d) - 2; + } + } + } + } + if (!expanded) + expanded = tsubst_pack_expansion (op, args, complain, in_decl); + } else expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op), args, complain, in_decl); @@ -21312,13 +21680,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; @@ -21959,6 +22321,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (DECL_NAME (t) == this_identifier && current_class_ptr) RETURN (current_class_ptr); + /* Parameters of non-templates map to themselves (e.g. in + expansion statement body). */ + if (DECL_CONTEXT (t) && !uses_template_parms (DECL_CONTEXT (t))) + RETURN (t); + /* This can happen for a parameter name used later in a function declaration (such as in a late-specified return type). Just make a dummy decl, since it's only used for its type. */ @@ -22175,12 +22542,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case OFFSET_REF: { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + /* We should only get here for an OFFSET_REF like A::m; a .* in a + template is represented as a DOTSTAR_EXPR. */ + gcc_checking_assert + (same_type_p (TREE_TYPE (t), TREE_TYPE (TREE_OPERAND (t, 1)))); tree op0 = RECUR (TREE_OPERAND (t, 0)); tree op1 = RECUR (TREE_OPERAND (t, 1)); + tree type = TREE_TYPE (op1); r = build2 (OFFSET_REF, type, op0, op1); PTRMEM_OK_P (r) = PTRMEM_OK_P (t); - if (!mark_used (TREE_OPERAND (r, 1), complain) + if (!mark_used (op1, complain) && !(complain & tf_error)) RETURN (error_mark_node); RETURN (r); @@ -22293,6 +22664,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) type1 = tsubst_expr (type1, args, complain, in_decl); tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args, complain, in_decl); + if (TRAIT_EXPR_KIND (t) == CPTK_STRUCTURED_BINDING_SIZE + && type1 != error_mark_node + && !processing_template_decl) + /* __builtin_structured_binding_size handled separately + to make it SFINAE friendly. */ + RETURN (finish_structured_binding_size (TRAIT_EXPR_LOCATION (t), + type1, complain)); RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t), TRAIT_EXPR_KIND (t), type1, type2)); } @@ -23237,7 +23615,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)) @@ -23484,9 +23862,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) @@ -23494,45 +23876,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; } @@ -24438,7 +24798,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), @@ -25778,10 +26139,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); @@ -27370,6 +27731,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 @@ -27750,6 +28115,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. */ @@ -27943,7 +28313,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. */ @@ -28056,12 +28428,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)) @@ -28078,13 +28454,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, @@ -28094,8 +28464,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) @@ -28112,8 +28484,6 @@ instantiate_pending_templates (int retries) last = *t; t = &(*t)->next; } - tinst_depth = 0; - set_refcount_ptr (current_tinst_level); } last_pending_template = last; } @@ -28839,6 +29209,24 @@ value_dependent_expression_p (tree expression) case SIZEOF_EXPR: if (SIZEOF_EXPR_TYPE_P (expression)) return dependent_type_p (TREE_TYPE (TREE_OPERAND (expression, 0))); + if (tree p = TREE_OPERAND (expression, 0)) + if (PACK_EXPANSION_P (p) + && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (p))) + { + tree d = PACK_EXPANSION_PATTERN (p); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + /* [temp.dep.constexpr]/4: + Expressions of the following form are value-dependent: + sizeof ... ( identifier ) + unless the identifier is a structured binding pack whose + initializer is not dependent. */ + if (TREE_CODE (d) == TREE_VEC + && !type_dependent_expression_p (TREE_VEC_ELT (d, 0))) + return false; + } + } /* FALLTHRU */ case ALIGNOF_EXPR: case TYPEID_EXPR: @@ -29352,6 +29740,22 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, tree op = TREE_OPERAND (*tp, 0); if (code == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (*tp)) op = TREE_TYPE (op); + else if (code == SIZEOF_EXPR + && PACK_EXPANSION_P (op) + && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op))) + { + tree d = PACK_EXPANSION_PATTERN (op); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + if (TREE_CODE (d) == TREE_VEC + && !type_dependent_expression_p (TREE_VEC_ELT (d, 0))) + { + *walk_subtrees = 0; + return NULL_TREE; + } + } + } if (TYPE_P (op)) { if (dependent_type_p (op)) @@ -30936,9 +31340,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)); @@ -31015,14 +31418,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* Substitute the deduced arguments plus the rewritten template parameters into f to get g. This covers the type, copyness, guideness, and explicit-specifier. */ - tree g; - { - /* Parms are to have DECL_CHAIN tsubsted, which would be skipped - if cp_unevaluated_operand. */ - cp_evaluated ev; - g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain, + tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain, /*use_spec_table=*/false); - } if (g == error_mark_node) continue; DECL_NAME (g) = name; @@ -31452,7 +31849,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree outer_targs, /* Be permissive with equivalent alias templates. */ tree u = get_underlying_template (tmpl); auto_diagnostic_group d; - diagnostic_t dk = (u == tmpl) ? DK_ERROR : DK_PEDWARN; + const enum diagnostics::kind dk = ((u == tmpl) + ? diagnostics::kind::error + : diagnostics::kind::pedwarn); bool complained = emit_diagnostic (dk, input_location, 0, "alias template deduction only available " @@ -32251,6 +32650,401 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl, } } +struct expansion_stmt_bc +{ + tree break_label; + tree continue_label; + hash_set<tree> *pset; + location_t loc; + bool in_switch; +}; + +/* Helper function for finish_expansion_stmt. Find BREAK_STMT (not + nested inside of other WHILE_STMT, FOR_STMT, DO_STMT, TEMPLATE_FOR_STMT + or SWITCH_STMT) or CONTINUE_STMT (not nested inside those except + perhaps SWITCH_STMT) and replace them with GOTO_EXPR to lazily created + label. */ + +static tree +expansion_stmt_find_bc_r (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + expansion_stmt_bc *bc_data = (expansion_stmt_bc *) data; + switch (TREE_CODE (t)) + { + case WHILE_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (WHILE_STMT); ++i) + if (&TREE_OPERAND (t, i) != &WHILE_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case FOR_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (FOR_STMT); ++i) + if (&TREE_OPERAND (t, i) != &FOR_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case DO_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (DO_STMT); ++i) + if (&TREE_OPERAND (t, i) != &DO_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case TEMPLATE_FOR_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (TEMPLATE_FOR_STMT); ++i) + if (&TREE_OPERAND (t, i) != &TEMPLATE_FOR_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case SWITCH_STMT: + if (!bc_data->in_switch) + { + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (SWITCH_STMT); ++i) + if (&TREE_OPERAND (t, i) != &SWITCH_STMT_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + bc_data->in_switch = true; + cp_walk_tree (&SWITCH_STMT_BODY (t), expansion_stmt_find_bc_r, + data, bc_data->pset); + bc_data->in_switch = false; + } + break; + case BREAK_STMT: + if (!bc_data->in_switch) + { + if (!bc_data->break_label) + { + bc_data->break_label = create_artificial_label (bc_data->loc); + TREE_USED (bc_data->break_label) = 1; + LABEL_DECL_BREAK (bc_data->break_label) = true; + } + *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node, + bc_data->break_label); + } + break; + case CONTINUE_STMT: + if (!bc_data->continue_label) + { + bc_data->continue_label = create_artificial_label (bc_data->loc); + TREE_USED (bc_data->continue_label) = 1; + LABEL_DECL_CONTINUE (bc_data->continue_label) = true; + } + *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node, + bc_data->continue_label); + break; + default: + if (TYPE_P (t)) + *walk_subtrees = 0; + break; + } + return NULL_TREE; +} + +/* Finish an expansion-statement. */ + +void +finish_expansion_stmt (tree expansion_stmt, tree args, + tsubst_flags_t complain, tree in_decl) +{ + tree expansion_init = TEMPLATE_FOR_EXPR (expansion_stmt); + if (error_operand_p (expansion_init)) + return; + + enum expansion_stmt_kind { + esk_none, + esk_iterating, + esk_destructuring, + esk_enumerating + } kind = esk_none; + + unsigned HOST_WIDE_INT n = 0; + tree range_decl = TEMPLATE_FOR_DECL (expansion_stmt); + bool is_decomp = false; + if (TREE_CODE (range_decl) == TREE_VEC) + { + is_decomp = true; + range_decl = TREE_VEC_ELT (range_decl, 0); + } + if (error_operand_p (range_decl)) + return; + + location_t loc = DECL_SOURCE_LOCATION (range_decl); + tree begin = NULL_TREE; + auto_vec<tree, 8> destruct_decls; + if (BRACE_ENCLOSED_INITIALIZER_P (expansion_init)) + { + /* Enumerating expansion statements. */ + kind = esk_enumerating; + n = CONSTRUCTOR_NELTS (expansion_init); + } + else if (TYPE_REF_P (TREE_TYPE (expansion_init)) + ? TREE_CODE (TREE_TYPE (TREE_TYPE (expansion_init))) != ARRAY_TYPE + : TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE) + { + tree range_temp, begin_expr, end_expr, iter_type; + range_temp = convert_from_reference (build_range_temp (expansion_init)); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr, tf_none); + if (begin_expr != error_mark_node && end_expr != error_mark_node) + { + kind = esk_iterating; + gcc_assert (iter_type); + } + } + if (kind == esk_iterating) + { + /* Iterating expansion statements. */ + tree end; + begin = cp_build_range_for_decls (loc, expansion_init, &end, true); + if (!error_operand_p (begin) && !error_operand_p (end)) + { + tree i = get_target_expr (begin); + tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE); + tree r = get_target_expr (build_zero_cst (ptrdiff_type_node)); + tree iinc = build_x_unary_op (loc, PREINCREMENT_EXPR, + TARGET_EXPR_SLOT (i), NULL_TREE, + tf_warning_or_error); + tree rinc = build2 (PREINCREMENT_EXPR, ptrdiff_type_node, + TARGET_EXPR_SLOT (r), + build_int_cst (ptrdiff_type_node, 1)); + WHILE_BODY (w) = build_compound_expr (loc, iinc, rinc); + WHILE_COND (w) = build_x_binary_op (loc, NE_EXPR, i, ERROR_MARK, + end, ERROR_MARK, NULL_TREE, NULL, + tf_warning_or_error); + tree e = build_compound_expr (loc, r, i); + e = build_compound_expr (loc, e, w); + e = build_compound_expr (loc, e, TARGET_EXPR_SLOT (r)); + e = cxx_constant_value (e); + if (tree_fits_uhwi_p (e)) + n = tree_to_uhwi (e); + } + } + else if (kind == esk_none) + { + kind = esk_destructuring; + HOST_WIDE_INT sz = cp_decomp_size (loc, TREE_TYPE (expansion_init), + tf_warning_or_error); + if (sz < 0) + return; + n = sz; + tree auto_node = make_auto (); + tree decomp_type = cp_build_reference_type (auto_node, true); + decomp_type = do_auto_deduction (decomp_type, expansion_init, auto_node); + tree decl = build_decl (loc, VAR_DECL, NULL_TREE, decomp_type); + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_DECLARED_CONSTEXPR_P (decl) + = DECL_DECLARED_CONSTEXPR_P (range_decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (decl) = 1; + if (n) + fit_decomposition_lang_decl (decl, NULL_TREE); + pushdecl (decl); + cp_decomp this_decomp; + this_decomp.count = n; + destruct_decls.safe_grow (n, true); + for (unsigned HOST_WIDE_INT i = 0; i < n; ++i) + { + tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, make_auto ()); + TREE_USED (this_decl) = 1; + DECL_ARTIFICIAL (this_decl) = 1; + DECL_DECLARED_CONSTEXPR_P (this_decl) + = DECL_DECLARED_CONSTEXPR_P (decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (this_decl) = 1; + pushdecl (this_decl); + this_decomp.decl = this_decl; + destruct_decls[i] = this_decl; + } + DECL_NAME (decl) = for_range__identifier; + cp_finish_decl (decl, expansion_init, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING, n ? &this_decomp : NULL); + DECL_NAME (decl) = NULL_TREE; + } + + expansion_stmt_bc bc_data = { NULL_TREE, NULL_TREE, NULL, loc, false }; + + for (unsigned HOST_WIDE_INT i = 0; i < n; ++i) + { + tree scope = do_pushlevel (sk_block); + bool revert_outer + = (current_binding_level->level_chain + && current_binding_level->level_chain->kind == sk_template_for); + /* Don't diagnose redeclaration of for-range-declaration decls. + The sk_template_for block is reused for the originally parsed + source as well as the lowered one. In the original one + redeclaration of the for-range-declaration decls in the substatement + should be diagnosed (i.e. declarations of the same name in sk_block + of the body vs. declarations in sk_template_for block). In the + lowered case, the sk_block added by do_pushlevel (sk_block) above + will be block in the lowering of each Si. Those blocks do redeclare + for-range-declaration, so temporarily change sk_template_for + kind to sk_block to avoid it being diagnosed as invalid. */ + if (revert_outer) + current_binding_level->level_chain->kind = sk_block; + tree type = TREE_TYPE (range_decl); + if (args) + type = tsubst (type, args, complain | tf_tst_ok, in_decl); + tree decl = build_decl (loc, VAR_DECL, DECL_NAME (range_decl), type); + DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (range_decl); + if (args) + apply_late_template_attributes (&decl, DECL_ATTRIBUTES (decl), + /*flags=*/0, args, complain, + in_decl); + + DECL_DECLARED_CONSTEXPR_P (decl) + = DECL_DECLARED_CONSTEXPR_P (range_decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (decl) = 1; + pushdecl (decl); + tree init = NULL_TREE; + switch (kind) + { + case esk_enumerating: + init = CONSTRUCTOR_ELT (expansion_init, i)->value; + break; + case esk_iterating: + tree iter_init, auto_node, iter_type, iter; + iter_init + = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK, + build_int_cst (ptrdiff_type_node, i), + ERROR_MARK, NULL_TREE, NULL, + tf_warning_or_error); + auto_node = make_auto (); + iter_type = do_auto_deduction (auto_node, iter_init, auto_node); + iter = build_decl (loc, VAR_DECL, NULL_TREE, iter_type); + TREE_USED (iter) = 1; + DECL_ARTIFICIAL (iter) = 1; + TREE_STATIC (iter) = 1; + DECL_DECLARED_CONSTEXPR_P (iter) = 1; + pushdecl (iter); + cp_finish_decl (iter, iter_init, /*is_constant_init*/false, + NULL_TREE, LOOKUP_ONLYCONVERTING); + init = build_x_indirect_ref (loc, iter, RO_UNARY_STAR, NULL_TREE, + tf_warning_or_error); + break; + case esk_destructuring: + init = convert_from_reference (destruct_decls[i]); + break; + default: + gcc_unreachable (); + } + cp_decomp this_decomp = {}; + if (is_decomp) + { + fit_decomposition_lang_decl (decl, NULL_TREE); + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + this_decomp.count = TREE_VEC_LENGTH (v) - 1; + for (unsigned i = 0; i < this_decomp.count; ++i) + { + tree this_decl + = build_decl (loc, VAR_DECL, + DECL_NAME (TREE_VEC_ELT (v, i + 1)), + make_auto ()); + TREE_USED (this_decl) = 1; + DECL_ARTIFICIAL (this_decl) = 1; + DECL_ATTRIBUTES (this_decl) + = DECL_ATTRIBUTES (TREE_VEC_ELT (v, i + 1)); + if (DECL_PACK_P (TREE_VEC_ELT (v, i + 1))) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = this_decl; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + tree type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = this_decl; + TREE_TYPE (this_decl) = type; + } + if (args) + apply_late_template_attributes (&this_decl, + DECL_ATTRIBUTES (this_decl), + /*flags=*/0, args, + complain, in_decl); + DECL_DECLARED_CONSTEXPR_P (this_decl) + = DECL_DECLARED_CONSTEXPR_P (decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (this_decl) = 1; + pushdecl (this_decl); + this_decomp.decl = this_decl; + } + } + cp_finish_decl (decl, init, false, NULL_TREE, + LOOKUP_ONLYCONVERTING, is_decomp ? &this_decomp : NULL); + if (revert_outer) + current_binding_level->level_chain->kind = sk_template_for; + tree targs = args; + if (args == NULL_TREE) + { + targs = make_tree_vec (1); + TREE_VEC_ELT (targs, 0) = build_int_cst (ptrdiff_type_node, i + 1); + } + if (args != NULL_TREE + || push_tinst_level_loc (expansion_stmt, targs, loc)) + { + local_specialization_stack lss (lss_copy); + register_local_specialization (decl, range_decl); + if (is_decomp) + { + tree d = this_decomp.decl; + unsigned int cnt = this_decomp.count; + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + for (unsigned int i = 0; i < cnt; ++i, d = DECL_CHAIN (d)) + register_local_specialization (d, TREE_VEC_ELT (v, cnt - i)); + } + tsubst_stmt (TEMPLATE_FOR_BODY (expansion_stmt), + targs, complain, in_decl ? in_decl : range_decl); + if (args == NULL_TREE) + pop_tinst_level (); + } + tree stmt = do_poplevel (scope); + if (stmt) + { + add_stmt (stmt); + hash_set<tree> pset; + bc_data.continue_label = NULL_TREE; + bc_data.pset = &pset; + cp_walk_tree (&stmt, expansion_stmt_find_bc_r, &bc_data, &pset); + if (bc_data.continue_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, + bc_data.continue_label)); + } + } + if (bc_data.break_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, bc_data.break_label)); + if (args == NULL_TREE) + { + TREE_TYPE (range_decl) = error_mark_node; + if (DECL_HAS_VALUE_EXPR_P (range_decl)) + { + SET_DECL_VALUE_EXPR (range_decl, NULL_TREE); + DECL_HAS_VALUE_EXPR_P (range_decl) = 0; + } + if (is_decomp) + { + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + for (int i = 1; i < TREE_VEC_LENGTH (v); ++i) + { + tree d = TREE_VEC_ELT (v, i); + TREE_TYPE (d) = error_mark_node; + if (DECL_HAS_VALUE_EXPR_P (d)) + { + SET_DECL_VALUE_EXPR (d, NULL_TREE); + DECL_HAS_VALUE_EXPR_P (d) = 0; + } + } + } + } +} + /* Set up the hash tables for template instantiations. */ void 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..58e6f94 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. */ @@ -677,7 +677,7 @@ do_poplevel (tree stmt_list) /* Begin a new scope. */ -static tree +tree do_pushlevel (scope_kind sk) { tree ret = push_stmt_list (); @@ -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); } @@ -1851,6 +1854,21 @@ finish_range_for_decl (tree range_for_stmt, tree decl, tree expr) RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block); } +/* Begin the scope of an expansion-statement. */ + +tree +begin_template_for_scope (tree *init) +{ + tree scope = do_pushlevel (sk_template_for); + + if (processing_template_decl) + *init = push_stmt_list (); + else + *init = NULL_TREE; + + return scope; +} + /* Finish a break-statement. */ tree @@ -2335,7 +2353,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, oconstraints[i] = constraint; if (parse_output_constraint (&constraint, i, ninputs, noutputs, - &allows_mem, &allows_reg, &is_inout)) + &allows_mem, &allows_reg, &is_inout, + nullptr)) { /* If the operand is going to end up in memory, mark it addressable. */ @@ -2394,7 +2413,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string, constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); bool constraint_parsed = parse_input_constraint (&constraint, i, ninputs, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); + oconstraints, &allows_mem, &allows_reg, + nullptr); /* If the operand is going to end up in memory, don't call decay_conversion. */ if (constraint_parsed && !allows_reg && allows_mem) @@ -2767,7 +2787,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 +3102,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 +3342,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 +3622,13 @@ finish_this_expr (void) { tree result = NULL_TREE; - if (current_class_ptr) - { - tree type = TREE_TYPE (current_class_ref); - - /* In a lambda expression, 'this' refers to the captured 'this'. */ - if (LAMBDA_TYPE_P (type)) - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type), true); - else - result = current_class_ptr; - } + if (current_class_ref && !LAMBDA_TYPE_P (TREE_TYPE (current_class_ref))) + result = current_class_ptr; + else if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + result = (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type), /*add*/true)); + else + gcc_checking_assert (!current_class_ptr); if (result) /* The keyword 'this' is a prvalue expression. */ @@ -3732,6 +3758,11 @@ finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr expr, if (!(complain & tf_warning)) return result; + /* These will never fold into a constant, so no need to check for + overflow for them. */ + if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) + return result; + tree result_ovl = result; tree expr_ovl = expr; @@ -3976,9 +4007,15 @@ finish_compound_literal (tree type, tree compound_literal, tree finish_fname (tree id) { - tree decl; - - decl = fname_decl (input_location, C_RID_CODE (id), id); + tree decl = fname_decl (input_location, C_RID_CODE (id), id); + /* [expr.prim.lambda.closure]/16 "Unless the compound-statement is that + of a consteval-block-declaration, a variable __func__ is implicitly + defined...". We could be in a consteval block in a function, though, + and then we shouldn't warn. */ + if (current_function_decl + && !current_nonlambda_function (/*only_skip_consteval_block_p=*/true)) + pedwarn (input_location, 0, "%qD is not defined outside of function scope", + decl); if (processing_template_decl && current_function_decl && decl != error_mark_node) decl = DECL_NAME (decl); @@ -4474,6 +4511,17 @@ baselink_for_fns (tree fns) return build_baselink (conv_path, access_path, fns, /*optype=*/NULL_TREE); } +/* Returns true iff we are currently parsing a lambda-declarator. */ + +static bool +parsing_lambda_declarator () +{ + cp_binding_level *b = current_binding_level; + while (b->kind == sk_template_parms || b->kind == sk_function_parms) + b = b->level_chain; + return b->kind == sk_lambda; +} + /* Returns true iff DECL is a variable from a function outside the current one. */ @@ -4488,7 +4536,15 @@ outer_var_p (tree decl) /* Don't get confused by temporaries. */ && DECL_NAME (decl) && (DECL_CONTEXT (decl) != current_function_decl - || parsing_nsdmi ())); + || parsing_nsdmi () + /* Also consider captures as outer vars if we are in + decltype in a lambda declarator as in: + auto l = [j=0]() -> decltype((j)) { ... } + for the sake of finish_decltype_type. + + (Similar issue also affects non-lambdas, but vexing parse + makes it more difficult to handle than lambdas.) */ + || parsing_lambda_declarator ())); } /* As above, but also checks that DECL is automatic. */ @@ -4534,7 +4590,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use) if (!mark_used (decl, complain)) return error_mark_node; - if (parsing_nsdmi ()) + if (parsing_nsdmi () || parsing_lambda_declarator ()) containing_function = NULL_TREE; if (containing_function && LAMBDA_FUNCTION_P (containing_function)) @@ -5088,22 +5144,32 @@ static tree finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain) { idx = maybe_constant_value (idx, NULL_TREE, mce_true); - if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx))) + if (!INTEGRAL_TYPE_P (TREE_TYPE (idx))) { if (complain & tf_error) - error ("pack index is not an integral constant"); + error ("pack index has non-integral type %qT", TREE_TYPE (idx)); + return error_mark_node; + } + if (TREE_CODE (idx) != INTEGER_CST) + { + if (complain & tf_error) + { + error ("pack index is not an integral constant"); + cxx_constant_value (idx); + } return error_mark_node; } if (tree_int_cst_sgn (idx) < 0) { if (complain & tf_error) - error ("pack index is negative"); + error ("pack index %qE is negative", idx); return error_mark_node; } if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) { if (complain & tf_error) - error ("pack index is out of range"); + error ("pack index %qE is out of range for pack of length %qd", + idx, TREE_VEC_LENGTH (types)); return error_mark_node; } return TREE_VEC_ELT (types, tree_to_shwi (idx)); @@ -6278,9 +6344,7 @@ handle_omp_array_sections (tree &c, enum c_omp_region_type ort) tree *tp = &OMP_CLAUSE_DECL (c); if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) - && TREE_CODE (*tp) == TREE_LIST - && TREE_PURPOSE (*tp) - && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + && OMP_ITERATOR_DECL_P (*tp)) tp = &TREE_VALUE (*tp); tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, @@ -6723,6 +6787,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 +7359,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. */ @@ -7603,7 +7785,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* We've reached the end of a list of expanded nodes. Reset the group start pointer. */ if (c == grp_sentinel) - grp_start_p = NULL; + { + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc != grp_sentinel; + gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + grp_start_p = NULL; + } switch (OMP_CLAUSE_CODE (c)) { @@ -8682,9 +8871,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* FALLTHRU */ case OMP_CLAUSE_AFFINITY: t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_PURPOSE (t) != last_iterators) last_iterators_remove @@ -8848,9 +9035,22 @@ 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: + if (OMP_CLAUSE_ITERATORS (c) + && cp_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c))) + { + t = error_mark_node; + break; + } + /* FALLTHRU */ case OMP_CLAUSE__CACHE_: { using namespace omp_addr_tokenizer; @@ -9754,6 +9954,11 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + if (reduction_seen < 0 && (ordered_seen || schedule_seen)) reduction_seen = -2; @@ -10467,6 +10672,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 +10687,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 +10701,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 +10772,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 +10824,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) @@ -12390,11 +12657,14 @@ cexpr_str::extract (location_t location, const char * & msg, int &len) CONDITION and the message text MESSAGE. LOCATION is the location of the static assertion in the source code. When MEMBER_P, this static assertion is a member of a class. If SHOW_EXPR_P is true, - print the condition (because it was instantiation-dependent). */ + print the condition (because it was instantiation-dependent). + If CONSTEVAL_BLOCK_P is true, this static assertion represents + a consteval block. */ void finish_static_assert (tree condition, tree message, location_t location, - bool member_p, bool show_expr_p) + bool member_p, bool show_expr_p, + bool consteval_block_p/*=false*/) { tsubst_flags_t complain = tf_warning_or_error; @@ -12422,6 +12692,7 @@ finish_static_assert (tree condition, tree message, location_t location, STATIC_ASSERT_CONDITION (assertion) = orig_condition; STATIC_ASSERT_MESSAGE (assertion) = cstr.message; STATIC_ASSERT_SOURCE_LOCATION (assertion) = location; + CONSTEVAL_BLOCK_P (assertion) = consteval_block_p; if (member_p) maybe_add_class_template_decl_list (current_class_type, @@ -12433,6 +12704,13 @@ finish_static_assert (tree condition, tree message, location_t location, return; } + /* Evaluate the consteval { }. This must be done only once. */ + if (consteval_block_p) + { + cxx_constant_value (condition); + return; + } + /* Fold the expression and convert it to a boolean value. */ condition = contextual_conv_bool (condition, complain); condition = fold_non_dependent_expr (condition, complain, @@ -12682,9 +12960,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, } else { - if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr)) - && current_function_decl - && LAMBDA_FUNCTION_P (current_function_decl)) + tree decl = STRIP_REFERENCE_REF (expr); + tree lam = current_lambda_expr (); + if (lam && outer_automatic_var_p (decl)) { /* [expr.prim.id.unqual]/3: If naming the entity from outside of an unevaluated operand within S would refer to an entity captured by @@ -12701,8 +12979,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, local variable inside decltype, not just decltype((x)) (PR83167). And we don't handle nested lambdas properly, where we need to consider the outer lambdas as well (PR112926). */ - tree decl = STRIP_REFERENCE_REF (expr); - tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); tree cap = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK, LOOK_want::HIDDEN_LAMBDA); @@ -12718,17 +12994,28 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, if (type && !TYPE_REF_P (type)) { - tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl)); - if (WILDCARD_TYPE_P (non_reference (obtype))) - /* We don't know what the eventual obtype quals will be. */ - goto dependent; - auto direct_type = [](tree t){ - if (INDIRECT_TYPE_P (t)) - return TREE_TYPE (t); - return t; - }; - int const quals = cp_type_quals (type) - | cp_type_quals (direct_type (obtype)); + int quals; + if (current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl) + && DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl)) + { + tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl)); + if (WILDCARD_TYPE_P (non_reference (obtype))) + /* We don't know what the eventual obtype quals will be. */ + goto dependent; + auto direct_type = [](tree t){ + if (INDIRECT_TYPE_P (t)) + return TREE_TYPE (t); + return t; + }; + quals = (cp_type_quals (type) + | cp_type_quals (direct_type (obtype))); + } + else + /* We are in the parameter clause, trailing return type, or + the requires clause and have no relevant c_f_decl yet. */ + quals = (LAMBDA_EXPR_CONST_QUAL_P (lam) + ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED); type = cp_build_qualified_type (type, quals); type = build_reference_type (type); } @@ -13156,6 +13443,18 @@ object_type_p (const_tree type) && !VOID_TYPE_P (type)); } +/* [defns.referenceable] True iff TYPE is a referenceable type. */ + +static bool +referenceable_type_p (const_tree type) +{ + return (TYPE_REF_P (type) + || object_type_p (type) + || (FUNC_OR_METHOD_TYPE_P (type) + && type_memfn_quals (type) == TYPE_UNQUALIFIED + && type_memfn_rqual (type) == REF_QUAL_NONE)); +} + /* Actually evaluates the trait. */ static bool @@ -13213,6 +13512,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 +13576,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,9 +13618,27 @@ 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); + case CPTK_IS_NOTHROW_RELOCATABLE: + if (trivially_relocatable_type_p (type1)) + return true; + else + { + type1 = strip_array_types (type1); + if (!referenceable_type_p (type1)) + return false; + tree arg = make_tree_vec (1); + TREE_VEC_ELT (arg, 0) + = cp_build_reference_type (type1, /*rval=*/true); + return (is_nothrow_xible (INIT_EXPR, type1, arg) + && is_nothrow_xible (BIT_NOT_EXPR, type1, NULL_TREE)); + } + case CPTK_IS_OBJECT: return object_type_p (type1); @@ -13328,6 +13657,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_REFERENCE: return type_code1 == REFERENCE_TYPE; + case CPTK_IS_REPLACEABLE: + return replaceable_type_p (type1); + case CPTK_IS_SAME: return same_type_p (type1, type2); @@ -13349,6 +13681,12 @@ 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_TRIVIALLY_RELOCATABLE: + return trivially_relocatable_type_p (type1); + case CPTK_IS_UNBOUNDED_ARRAY: return array_of_unknown_bound_p (type1); @@ -13372,8 +13710,11 @@ 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, __builtin_type_order and __builtin_structured_binding_size + are handled in finish_trait_expr. */ case CPTK_RANK: + case CPTK_TYPE_ORDER: + case CPTK_STRUCTURED_BINDING_SIZE: gcc_unreachable (); #define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ @@ -13430,7 +13771,8 @@ check_trait_type (tree type, int kind = 1) type = complete_type (strip_array_types (type)); if (!COMPLETE_TYPE_P (type) - && cxx_incomplete_type_diagnostic (NULL_TREE, type, DK_PERMERROR) + && cxx_incomplete_type_diagnostic (NULL_TREE, type, + diagnostics::kind::permerror) && !flag_permissive) return false; return true; @@ -13477,16 +13819,25 @@ same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2) (non_reference (to), non_reference (from)))); } -/* [defns.referenceable] True iff TYPE is a referenceable type. */ +/* Helper for finish_trait_expr and tsubst_expr. Handle + CPTK_STRUCTURED_BINDING_SIZE in possibly SFINAE-friendly + way. */ -static bool -referenceable_type_p (const_tree type) +tree +finish_structured_binding_size (location_t loc, tree type, + tsubst_flags_t complain) { - return (TYPE_REF_P (type) - || object_type_p (type) - || (FUNC_OR_METHOD_TYPE_P (type) - && (type_memfn_quals (type) == TYPE_UNQUALIFIED - && type_memfn_rqual (type) == REF_QUAL_NONE))); + if (TYPE_REF_P (type)) + { + if (complain & tf_error) + error_at (loc, "%qs argument %qT is a reference", + "__builtin_structured_binding_size", type); + return error_mark_node; + } + HOST_WIDE_INT ret = cp_decomp_size (loc, type, complain); + if (ret == -1) + return error_mark_node; + return maybe_wrap_with_location (build_int_cst (size_type_node, ret), loc); } /* Process a trait expression. */ @@ -13501,8 +13852,14 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) if (processing_template_decl) { tree trait_expr = make_node (TRAIT_EXPR); - if (kind == CPTK_RANK) + if (kind == CPTK_RANK || kind == CPTK_STRUCTURED_BINDING_SIZE) 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 +13878,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; @@ -13528,8 +13888,11 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_LITERAL_TYPE: case CPTK_IS_POD: case CPTK_IS_STD_LAYOUT: + case CPTK_IS_REPLACEABLE: + case CPTK_IS_NOTHROW_RELOCATABLE: case CPTK_IS_TRIVIAL: case CPTK_IS_TRIVIALLY_COPYABLE: + case CPTK_IS_TRIVIALLY_RELOCATABLE: case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: if (!check_trait_type (type1, /* kind = */ 2)) return error_mark_node; @@ -13606,9 +13969,23 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_UNBOUNDED_ARRAY: case CPTK_IS_UNION: case CPTK_IS_VOLATILE: - case CPTK_RANK: break; + case CPTK_RANK: + { + size_t rank = 0; + for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1)) + ++rank; + return maybe_wrap_with_location (build_int_cst (size_type_node, rank), + loc); + } + + case CPTK_TYPE_ORDER: + return maybe_wrap_with_location (type_order_value (type1, type2), loc); + + case CPTK_STRUCTURED_BINDING_SIZE: + return finish_structured_binding_size (loc, type1, tf_warning_or_error); + case CPTK_IS_LAYOUT_COMPATIBLE: if (!array_of_unknown_bound_p (type1) && TREE_CODE (type1) != VOID_TYPE @@ -13638,18 +14015,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) gcc_unreachable (); } - tree val; - if (kind == CPTK_RANK) - { - size_t rank = 0; - for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1)) - ++rank; - val = build_int_cst (size_type_node, rank); - } - else - val = (trait_expr_value (kind, type1, type2) - ? boolean_true_node : boolean_false_node); - + tree val = (trait_expr_value (kind, type1, type2) + ? boolean_true_node : boolean_false_node); return maybe_wrap_with_location (val, loc); } @@ -13846,7 +14213,7 @@ apply_deduced_return_type (tree fco, tree return_type) result); DECL_RESULT (fco) = result; - if (!processing_template_decl) + if (!uses_template_parms (fco)) if (function *fun = DECL_STRUCT_FUNCTION (fco)) { bool aggr = aggregate_value_p (result, fco); diff --git a/gcc/cp/std-name-hint.h b/gcc/cp/std-name-hint.h index dde2f9b..c5f8004 100644 --- a/gcc/cp/std-name-hint.h +++ b/gcc/cp/std-name-hint.h @@ -144,979 +144,979 @@ std_name_hint_lookup::find (const char *str, size_t len) static const struct std_name_hint wordlist[] = { -#line 130 "../../src/gcc/cp/std-name-hint.gperf" +#line 130 "std-name-hint.gperf" {"regular", "<concepts>", cxx20}, -#line 292 "../../src/gcc/cp/std-name-hint.gperf" +#line 292 "std-name-hint.gperf" {"reverse_iterator", "<iterator>", cxx98}, -#line 454 "../../src/gcc/cp/std-name-hint.gperf" +#line 454 "std-name-hint.gperf" {"range_error", "<stdexcept>", cxx98}, -#line 408 "../../src/gcc/cp/std-name-hint.gperf" +#line 408 "std-name-hint.gperf" {"set", "<set>", cxx98}, -#line 231 "../../src/gcc/cp/std-name-hint.gperf" +#line 231 "std-name-hint.gperf" {"setbase", "<iomanip>", cxx98}, -#line 325 "../../src/gcc/cp/std-name-hint.gperf" +#line 325 "std-name-hint.gperf" {"reinterpret_pointer_cast", "<memory>", cxx17}, -#line 288 "../../src/gcc/cp/std-name-hint.gperf" +#line 288 "std-name-hint.gperf" {"next", "<iterator>", cxx11}, -#line 171 "../../src/gcc/cp/std-name-hint.gperf" +#line 171 "std-name-hint.gperf" {"format", "<format>", cxx20}, -#line 181 "../../src/gcc/cp/std-name-hint.gperf" +#line 181 "std-name-hint.gperf" {"formatter", "<format>", cxx20}, -#line 196 "../../src/gcc/cp/std-name-hint.gperf" +#line 196 "std-name-hint.gperf" {"basic_filebuf", "<fstream>", cxx98}, -#line 575 "../../src/gcc/cp/std-name-hint.gperf" +#line 575 "std-name-hint.gperf" {"pair", "<utility>", cxx98}, -#line 276 "../../src/gcc/cp/std-name-hint.gperf" +#line 276 "std-name-hint.gperf" {"begin", "<iterator>", cxx11}, -#line 179 "../../src/gcc/cp/std-name-hint.gperf" +#line 179 "std-name-hint.gperf" {"formattable", "<format>", cxx23}, -#line 541 "../../src/gcc/cp/std-name-hint.gperf" +#line 541 "std-name-hint.gperf" {"bad_cast", "<typeinfo>", cxx98}, -#line 233 "../../src/gcc/cp/std-name-hint.gperf" +#line 233 "std-name-hint.gperf" {"setiosflags", "<iomanip>", cxx98}, -#line 393 "../../src/gcc/cp/std-name-hint.gperf" +#line 393 "std-name-hint.gperf" {"print", "<print>", cxx23}, -#line 221 "../../src/gcc/cp/std-name-hint.gperf" +#line 221 "std-name-hint.gperf" {"promise", "<future>", cxx11}, -#line 581 "../../src/gcc/cp/std-name-hint.gperf" +#line 581 "std-name-hint.gperf" {"bad_variant_access", "<variant>", cxx17}, -#line 328 "../../src/gcc/cp/std-name-hint.gperf" +#line 328 "std-name-hint.gperf" {"to_address", "<memory>", cxx20}, -#line 420 "../../src/gcc/cp/std-name-hint.gperf" +#line 420 "std-name-hint.gperf" {"basic_spanbuf", "<spanstream>", cxx23}, -#line 106 "../../src/gcc/cp/std-name-hint.gperf" +#line 106 "std-name-hint.gperf" {"same_as", "<concepts>", cxx20}, -#line 336 "../../src/gcc/cp/std-name-hint.gperf" +#line 336 "std-name-hint.gperf" {"pmr", "<memory_resource>", cxx17}, -#line 180 "../../src/gcc/cp/std-name-hint.gperf" +#line 180 "std-name-hint.gperf" {"formatted_size", "<format>", cxx20}, -#line 275 "../../src/gcc/cp/std-name-hint.gperf" +#line 275 "std-name-hint.gperf" {"back_inserter", "<iterator>", cxx98}, -#line 251 "../../src/gcc/cp/std-name-hint.gperf" +#line 251 "std-name-hint.gperf" {"nouppercase", "<ios>", cxx98}, -#line 250 "../../src/gcc/cp/std-name-hint.gperf" +#line 250 "std-name-hint.gperf" {"nounitbuf", "<ios>", cxx98}, -#line 433 "../../src/gcc/cp/std-name-hint.gperf" +#line 433 "std-name-hint.gperf" {"basic_stringbuf", "<sstream>", cxx98}, -#line 592 "../../src/gcc/cp/std-name-hint.gperf" +#line 592 "std-name-hint.gperf" {"vector", "<vector>", cxx98}, -#line 246 "../../src/gcc/cp/std-name-hint.gperf" +#line 246 "std-name-hint.gperf" {"noshowbase", "<ios>", cxx98}, -#line 219 "../../src/gcc/cp/std-name-hint.gperf" +#line 219 "std-name-hint.gperf" {"future", "<future>", cxx11}, -#line 340 "../../src/gcc/cp/std-name-hint.gperf" +#line 340 "std-name-hint.gperf" {"pmr::new_delete_resource", "<memory_resource>", cxx17}, -#line 337 "../../src/gcc/cp/std-name-hint.gperf" +#line 337 "std-name-hint.gperf" {"pmr::get_default_resource", "<memory_resource>", cxx17}, -#line 343 "../../src/gcc/cp/std-name-hint.gperf" +#line 343 "std-name-hint.gperf" {"pmr::set_default_resource", "<memory_resource>", cxx17}, -#line 455 "../../src/gcc/cp/std-name-hint.gperf" +#line 455 "std-name-hint.gperf" {"runtime_error", "<stdexcept>", cxx98}, -#line 516 "../../src/gcc/cp/std-name-hint.gperf" +#line 516 "std-name-hint.gperf" {"tuple", "<tuple>", cxx11}, -#line 132 "../../src/gcc/cp/std-name-hint.gperf" +#line 132 "std-name-hint.gperf" {"regular_invocable", "<concepts>", cxx20}, -#line 116 "../../src/gcc/cp/std-name-hint.gperf" +#line 116 "std-name-hint.gperf" {"swappable", "<concepts>", cxx20}, -#line 186 "../../src/gcc/cp/std-name-hint.gperf" +#line 186 "std-name-hint.gperf" {"runtime_format", "<format>", cxx26}, -#line 211 "../../src/gcc/cp/std-name-hint.gperf" +#line 211 "std-name-hint.gperf" {"not_fn", "<functional>", cxx17}, -#line 142 "../../src/gcc/cp/std-name-hint.gperf" +#line 142 "std-name-hint.gperf" {"byte", "<cstddef>", cxx17}, -#line 518 "../../src/gcc/cp/std-name-hint.gperf" +#line 518 "std-name-hint.gperf" {"tuple_element", "<tuple>", cxx11}, -#line 519 "../../src/gcc/cp/std-name-hint.gperf" +#line 519 "std-name-hint.gperf" {"tuple_element_t", "<tuple>", cxx14}, -#line 584 "../../src/gcc/cp/std-name-hint.gperf" +#line 584 "std-name-hint.gperf" {"variant", "<variant>", cxx17}, -#line 386 "../../src/gcc/cp/std-name-hint.gperf" +#line 386 "std-name-hint.gperf" {"ends", "<ostream>", cxx98}, -#line 520 "../../src/gcc/cp/std-name-hint.gperf" +#line 520 "std-name-hint.gperf" {"tuple_size", "<tuple>", cxx11}, -#line 123 "../../src/gcc/cp/std-name-hint.gperf" +#line 123 "std-name-hint.gperf" {"equality_comparable", "<concepts>", cxx20}, -#line 247 "../../src/gcc/cp/std-name-hint.gperf" +#line 247 "std-name-hint.gperf" {"noshowpoint", "<ios>", cxx98}, -#line 394 "../../src/gcc/cp/std-name-hint.gperf" +#line 394 "std-name-hint.gperf" {"println", "<print>", cxx23}, -#line 248 "../../src/gcc/cp/std-name-hint.gperf" +#line 248 "std-name-hint.gperf" {"noshowpos", "<ios>", cxx98}, -#line 388 "../../src/gcc/cp/std-name-hint.gperf" +#line 388 "std-name-hint.gperf" {"flush_emit", "<ostream>", cxx20}, -#line 585 "../../src/gcc/cp/std-name-hint.gperf" +#line 585 "std-name-hint.gperf" {"variant_alternative", "<variant>", cxx17}, -#line 537 "../../src/gcc/cp/std-name-hint.gperf" +#line 537 "std-name-hint.gperf" {"void_t", "<type_traits>", cxx17}, -#line 586 "../../src/gcc/cp/std-name-hint.gperf" +#line 586 "std-name-hint.gperf" {"variant_alternative_t", "<variant>", cxx17}, -#line 134 "../../src/gcc/cp/std-name-hint.gperf" +#line 134 "std-name-hint.gperf" {"relation", "<concepts>", cxx20}, -#line 461 "../../src/gcc/cp/std-name-hint.gperf" +#line 461 "std-name-hint.gperf" {"float32_t", "<stdfloat>", cxx23}, -#line 459 "../../src/gcc/cp/std-name-hint.gperf" +#line 459 "std-name-hint.gperf" {"float128_t", "<stdfloat>", cxx23}, -#line 381 "../../src/gcc/cp/std-name-hint.gperf" +#line 381 "std-name-hint.gperf" {"nullopt", "<optional>", cxx17}, -#line 291 "../../src/gcc/cp/std-name-hint.gperf" +#line 291 "std-name-hint.gperf" {"prev", "<iterator>", cxx11}, -#line 425 "../../src/gcc/cp/std-name-hint.gperf" +#line 425 "std-name-hint.gperf" {"spanbuf", "<spanstream>", cxx23}, -#line 513 "../../src/gcc/cp/std-name-hint.gperf" +#line 513 "std-name-hint.gperf" {"make_from_tuple", "<tuple>", cxx17}, -#line 253 "../../src/gcc/cp/std-name-hint.gperf" +#line 253 "std-name-hint.gperf" {"right", "<ios>", cxx98}, -#line 210 "../../src/gcc/cp/std-name-hint.gperf" +#line 210 "std-name-hint.gperf" {"mem_fn", "<functional>", cxx11}, -#line 515 "../../src/gcc/cp/std-name-hint.gperf" +#line 515 "std-name-hint.gperf" {"tie", "<tuple>", cxx11}, -#line 197 "../../src/gcc/cp/std-name-hint.gperf" +#line 197 "std-name-hint.gperf" {"basic_fstream", "<fstream>", cxx98}, -#line 573 "../../src/gcc/cp/std-name-hint.gperf" +#line 573 "std-name-hint.gperf" {"move", "<utility>", cxx11}, -#line 462 "../../src/gcc/cp/std-name-hint.gperf" +#line 462 "std-name-hint.gperf" {"float64_t", "<stdfloat>", cxx23}, -#line 127 "../../src/gcc/cp/std-name-hint.gperf" +#line 127 "std-name-hint.gperf" {"movable", "<concepts>", cxx20}, -#line 282 "../../src/gcc/cp/std-name-hint.gperf" +#line 282 "std-name-hint.gperf" {"front_inserter", "<iterator>", cxx98}, -#line 296 "../../src/gcc/cp/std-name-hint.gperf" +#line 296 "std-name-hint.gperf" {"map", "<map>", cxx98}, -#line 460 "../../src/gcc/cp/std-name-hint.gperf" +#line 460 "std-name-hint.gperf" {"float16_t", "<stdfloat>", cxx23}, -#line 56 "../../src/gcc/cp/std-name-hint.gperf" +#line 56 "std-name-hint.gperf" {"bitset", "<bitset>", cxx11}, -#line 205 "../../src/gcc/cp/std-name-hint.gperf" +#line 205 "std-name-hint.gperf" {"bind_front", "<functional>", cxx20}, -#line 574 "../../src/gcc/cp/std-name-hint.gperf" +#line 574 "std-name-hint.gperf" {"move_if_noexcept", "<utility>", cxx11}, -#line 274 "../../src/gcc/cp/std-name-hint.gperf" +#line 274 "std-name-hint.gperf" {"advance", "<iterator>", cxx98}, -#line 287 "../../src/gcc/cp/std-name-hint.gperf" +#line 287 "std-name-hint.gperf" {"move_iterator", "<iterator>", cxx11}, -#line 161 "../../src/gcc/cp/std-name-hint.gperf" +#line 161 "std-name-hint.gperf" {"terminate", "<exception>", cxx98}, -#line 531 "../../src/gcc/cp/std-name-hint.gperf" +#line 531 "std-name-hint.gperf" {"negation", "<type_traits>", cxx17}, -#line 318 "../../src/gcc/cp/std-name-hint.gperf" +#line 318 "std-name-hint.gperf" {"make_obj_using_allocator", "<memory>", cxx20}, -#line 321 "../../src/gcc/cp/std-name-hint.gperf" +#line 321 "std-name-hint.gperf" {"make_unique", "<memory>", cxx14}, -#line 255 "../../src/gcc/cp/std-name-hint.gperf" +#line 255 "std-name-hint.gperf" {"showbase", "<ios>", cxx98}, -#line 416 "../../src/gcc/cp/std-name-hint.gperf" +#line 416 "std-name-hint.gperf" {"span", "<span>", cxx20}, -#line 185 "../../src/gcc/cp/std-name-hint.gperf" +#line 185 "std-name-hint.gperf" {"range_formatter", "<format>", cxx23}, -#line 299 "../../src/gcc/cp/std-name-hint.gperf" +#line 299 "std-name-hint.gperf" {"addressof", "<memory>", cxx11}, -#line 571 "../../src/gcc/cp/std-name-hint.gperf" +#line 571 "std-name-hint.gperf" {"make_integer_sequence", "<utility>", cxx14}, -#line 184 "../../src/gcc/cp/std-name-hint.gperf" +#line 184 "std-name-hint.gperf" {"range_format", "<format>", cxx23}, -#line 322 "../../src/gcc/cp/std-name-hint.gperf" +#line 322 "std-name-hint.gperf" {"make_unique_for_overwrite", "<memory>", cxx20}, -#line 421 "../../src/gcc/cp/std-name-hint.gperf" +#line 421 "std-name-hint.gperf" {"basic_spanstream", "<spanstream>", cxx23}, -#line 257 "../../src/gcc/cp/std-name-hint.gperf" +#line 257 "std-name-hint.gperf" {"showpos", "<ios>", cxx98}, -#line 550 "../../src/gcc/cp/std-name-hint.gperf" +#line 550 "std-name-hint.gperf" {"as_const", "<utility>", cxx17}, -#line 308 "../../src/gcc/cp/std-name-hint.gperf" +#line 308 "std-name-hint.gperf" {"bad_weak_ptr", "<memory>", cxx11}, -#line 168 "../../src/gcc/cp/std-name-hint.gperf" +#line 168 "std-name-hint.gperf" {"basic_format_context", "<format>", cxx20}, -#line 434 "../../src/gcc/cp/std-name-hint.gperf" +#line 434 "std-name-hint.gperf" {"basic_stringstream", "<sstream>", cxx98}, -#line 539 "../../src/gcc/cp/std-name-hint.gperf" +#line 539 "std-name-hint.gperf" {"type_index", "<typeindex>", cxx11}, -#line 169 "../../src/gcc/cp/std-name-hint.gperf" +#line 169 "std-name-hint.gperf" {"basic_format_parse_context", "<format>", cxx20}, -#line 160 "../../src/gcc/cp/std-name-hint.gperf" +#line 160 "std-name-hint.gperf" {"make_exception_ptr", "<exception>", cxx11}, -#line 468 "../../src/gcc/cp/std-name-hint.gperf" +#line 468 "std-name-hint.gperf" {"basic_streambuf", "<streambuf>", cxx98}, -#line 167 "../../src/gcc/cp/std-name-hint.gperf" +#line 167 "std-name-hint.gperf" {"basic_format_args", "<format>", cxx20}, -#line 588 "../../src/gcc/cp/std-name-hint.gperf" +#line 588 "std-name-hint.gperf" {"variant_size", "<variant>", cxx17}, -#line 407 "../../src/gcc/cp/std-name-hint.gperf" +#line 407 "std-name-hint.gperf" {"multiset", "<set>", cxx98}, -#line 133 "../../src/gcc/cp/std-name-hint.gperf" +#line 133 "std-name-hint.gperf" {"predicate", "<concepts>", cxx20}, -#line 397 "../../src/gcc/cp/std-name-hint.gperf" +#line 397 "std-name-hint.gperf" {"queue", "<queue>", cxx98}, -#line 353 "../../src/gcc/cp/std-name-hint.gperf" +#line 353 "std-name-hint.gperf" {"recursive_timed_mutex", "<mutex>", cxx11}, -#line 399 "../../src/gcc/cp/std-name-hint.gperf" +#line 399 "std-name-hint.gperf" {"ranges::enable_borrowed_range", "<ranges>", cxx20}, -#line 533 "../../src/gcc/cp/std-name-hint.gperf" +#line 533 "std-name-hint.gperf" {"remove_cvref", "<type_traits>", cxx20}, -#line 206 "../../src/gcc/cp/std-name-hint.gperf" +#line 206 "std-name-hint.gperf" {"function", "<functional>", cxx11}, -#line 532 "../../src/gcc/cp/std-name-hint.gperf" +#line 532 "std-name-hint.gperf" {"negation_v", "<type_traits>", cxx17}, -#line 534 "../../src/gcc/cp/std-name-hint.gperf" +#line 534 "std-name-hint.gperf" {"remove_cvref_t", "<type_traits>", cxx20}, -#line 289 "../../src/gcc/cp/std-name-hint.gperf" +#line 289 "std-name-hint.gperf" {"ostream_iterator", "<iterator>", cxx98}, -#line 587 "../../src/gcc/cp/std-name-hint.gperf" +#line 587 "std-name-hint.gperf" {"variant_npos", "<variant>", cxx17}, -#line 244 "../../src/gcc/cp/std-name-hint.gperf" +#line 244 "std-name-hint.gperf" {"left", "<ios>", cxx98}, -#line 200 "../../src/gcc/cp/std-name-hint.gperf" +#line 200 "std-name-hint.gperf" {"fstream", "<fstream>", cxx98}, -#line 590 "../../src/gcc/cp/std-name-hint.gperf" +#line 590 "std-name-hint.gperf" {"visit", "<variant>", cxx17}, -#line 208 "../../src/gcc/cp/std-name-hint.gperf" +#line 208 "std-name-hint.gperf" {"invoke", "<functional>", cxx17}, -#line 137 "../../src/gcc/cp/std-name-hint.gperf" +#line 137 "std-name-hint.gperf" {"ranges::swap", "<concepts>", cxx20}, -#line 283 "../../src/gcc/cp/std-name-hint.gperf" +#line 283 "std-name-hint.gperf" {"inserter", "<iterator>", cxx98}, -#line 362 "../../src/gcc/cp/std-name-hint.gperf" +#line 362 "std-name-hint.gperf" {"launder", "<new>", cxx17}, -#line 228 "../../src/gcc/cp/std-name-hint.gperf" +#line 228 "std-name-hint.gperf" {"put_time", "<iomanip>", cxx11}, -#line 237 "../../src/gcc/cp/std-name-hint.gperf" +#line 237 "std-name-hint.gperf" {"boolalpha", "<ios>", cxx98}, -#line 361 "../../src/gcc/cp/std-name-hint.gperf" +#line 361 "std-name-hint.gperf" {"hardware_destructive_interference_size", "<new>", cxx17}, -#line 199 "../../src/gcc/cp/std-name-hint.gperf" +#line 199 "std-name-hint.gperf" {"basic_ofstream", "<fstream>", cxx98}, -#line 324 "../../src/gcc/cp/std-name-hint.gperf" +#line 324 "std-name-hint.gperf" {"pointer_traits", "<memory>", cxx11}, -#line 131 "../../src/gcc/cp/std-name-hint.gperf" +#line 131 "std-name-hint.gperf" {"invocable", "<concepts>", cxx20}, -#line 426 "../../src/gcc/cp/std-name-hint.gperf" +#line 426 "std-name-hint.gperf" {"spanstream", "<spanstream>", cxx23}, -#line 182 "../../src/gcc/cp/std-name-hint.gperf" +#line 182 "std-name-hint.gperf" {"make_format_args", "<format>", cxx20}, -#line 121 "../../src/gcc/cp/std-name-hint.gperf" +#line 121 "std-name-hint.gperf" {"move_constructible", "<concepts>", cxx20}, -#line 114 "../../src/gcc/cp/std-name-hint.gperf" +#line 114 "std-name-hint.gperf" {"floating_point", "<concepts>", cxx20}, -#line 258 "../../src/gcc/cp/std-name-hint.gperf" +#line 258 "std-name-hint.gperf" {"skipws", "<ios>", cxx98}, -#line 241 "../../src/gcc/cp/std-name-hint.gperf" +#line 241 "std-name-hint.gperf" {"hex", "<ios>", cxx98}, -#line 568 "../../src/gcc/cp/std-name-hint.gperf" +#line 568 "std-name-hint.gperf" {"index_sequence_for", "<utility>", cxx14}, -#line 567 "../../src/gcc/cp/std-name-hint.gperf" +#line 567 "std-name-hint.gperf" {"index_sequence", "<utility>", cxx14}, -#line 350 "../../src/gcc/cp/std-name-hint.gperf" +#line 350 "std-name-hint.gperf" {"mutex", "<mutex>", cxx11}, -#line 284 "../../src/gcc/cp/std-name-hint.gperf" +#line 284 "std-name-hint.gperf" {"istream_iterator", "<iterator>", cxx98}, -#line 334 "../../src/gcc/cp/std-name-hint.gperf" +#line 334 "std-name-hint.gperf" {"weak_ptr", "<memory>", cxx11}, -#line 173 "../../src/gcc/cp/std-name-hint.gperf" +#line 173 "std-name-hint.gperf" {"format_context", "<format>", cxx20}, -#line 451 "../../src/gcc/cp/std-name-hint.gperf" +#line 451 "std-name-hint.gperf" {"logic_error", "<stdexcept>", cxx98}, -#line 372 "../../src/gcc/cp/std-name-hint.gperf" +#line 372 "std-name-hint.gperf" {"numbers::ln2_v", "<numbers>", cxx20}, -#line 371 "../../src/gcc/cp/std-name-hint.gperf" +#line 371 "std-name-hint.gperf" {"numbers::ln10_v", "<numbers>", cxx20}, -#line 368 "../../src/gcc/cp/std-name-hint.gperf" +#line 368 "std-name-hint.gperf" {"numbers::inv_pi_v", "<numbers>", cxx20}, -#line 235 "../../src/gcc/cp/std-name-hint.gperf" +#line 235 "std-name-hint.gperf" {"setw", "<iomanip>", cxx98}, -#line 369 "../../src/gcc/cp/std-name-hint.gperf" +#line 369 "std-name-hint.gperf" {"numbers::inv_sqrt3_v", "<numbers>", cxx20}, -#line 370 "../../src/gcc/cp/std-name-hint.gperf" +#line 370 "std-name-hint.gperf" {"numbers::inv_sqrtpi_v", "<numbers>", cxx20}, -#line 230 "../../src/gcc/cp/std-name-hint.gperf" +#line 230 "std-name-hint.gperf" {"resetiosflags", "<iomanip>", cxx98}, -#line 303 "../../src/gcc/cp/std-name-hint.gperf" +#line 303 "std-name-hint.gperf" {"allocator", "<memory>", cxx98}, -#line 135 "../../src/gcc/cp/std-name-hint.gperf" +#line 135 "std-name-hint.gperf" {"equivalence_relation", "<concepts>", cxx20}, -#line 272 "../../src/gcc/cp/std-name-hint.gperf" +#line 272 "std-name-hint.gperf" {"ws", "<istream>", cxx98}, -#line 44 "../../src/gcc/cp/std-name-hint.gperf" +#line 44 "std-name-hint.gperf" {"any_cast", "<any>", cxx17}, -#line 198 "../../src/gcc/cp/std-name-hint.gperf" +#line 198 "std-name-hint.gperf" {"basic_ifstream", "<fstream>", cxx98}, -#line 175 "../../src/gcc/cp/std-name-hint.gperf" +#line 175 "std-name-hint.gperf" {"format_parse_context", "<format>", cxx20}, -#line 341 "../../src/gcc/cp/std-name-hint.gperf" +#line 341 "std-name-hint.gperf" {"pmr::polymorphic_allocator", "<memory_resource>", cxx17}, -#line 419 "../../src/gcc/cp/std-name-hint.gperf" +#line 419 "std-name-hint.gperf" {"basic_ospanstream", "<spanstream>", cxx23}, -#line 572 "../../src/gcc/cp/std-name-hint.gperf" +#line 572 "std-name-hint.gperf" {"make_pair", "<utility>", cxx98}, -#line 172 "../../src/gcc/cp/std-name-hint.gperf" +#line 172 "std-name-hint.gperf" {"format_args", "<format>", cxx20}, -#line 475 "../../src/gcc/cp/std-name-hint.gperf" +#line 475 "std-name-hint.gperf" {"stof", "<string>", cxx11}, -#line 339 "../../src/gcc/cp/std-name-hint.gperf" +#line 339 "std-name-hint.gperf" {"pmr::monotonic_buffer_resource", "<memory_resource>", cxx17}, -#line 342 "../../src/gcc/cp/std-name-hint.gperf" +#line 342 "std-name-hint.gperf" {"pmr::pool_options", "<memory_resource>", cxx17}, -#line 256 "../../src/gcc/cp/std-name-hint.gperf" +#line 256 "std-name-hint.gperf" {"showpoint", "<ios>", cxx98}, -#line 446 "../../src/gcc/cp/std-name-hint.gperf" +#line 446 "std-name-hint.gperf" {"stacktrace", "<stacktrace>", cxx23}, -#line 589 "../../src/gcc/cp/std-name-hint.gperf" +#line 589 "std-name-hint.gperf" {"variant_size_v", "<variant>", cxx17}, -#line 212 "../../src/gcc/cp/std-name-hint.gperf" +#line 212 "std-name-hint.gperf" {"reference_wrapper", "<functional>", cxx11}, -#line 262 "../../src/gcc/cp/std-name-hint.gperf" +#line 262 "std-name-hint.gperf" {"cerr", "<iostream>", cxx98}, -#line 300 "../../src/gcc/cp/std-name-hint.gperf" +#line 300 "std-name-hint.gperf" {"align", "<memory>", cxx11}, -#line 438 "../../src/gcc/cp/std-name-hint.gperf" +#line 438 "std-name-hint.gperf" {"stringbuf", "<sstream>", cxx98}, -#line 469 "../../src/gcc/cp/std-name-hint.gperf" +#line 469 "std-name-hint.gperf" {"streambuf", "<streambuf>", cxx98}, -#line 306 "../../src/gcc/cp/std-name-hint.gperf" +#line 306 "std-name-hint.gperf" {"allocator_traits", "<memory>", cxx11}, -#line 183 "../../src/gcc/cp/std-name-hint.gperf" +#line 183 "std-name-hint.gperf" {"make_wformat_args", "<format>", cxx20}, -#line 583 "../../src/gcc/cp/std-name-hint.gperf" +#line 583 "std-name-hint.gperf" {"monostate", "<variant>", cxx17}, -#line 387 "../../src/gcc/cp/std-name-hint.gperf" +#line 387 "std-name-hint.gperf" {"flush", "<ostream>", cxx98}, -#line 527 "../../src/gcc/cp/std-name-hint.gperf" +#line 527 "std-name-hint.gperf" {"enable_if", "<type_traits>", cxx11}, -#line 352 "../../src/gcc/cp/std-name-hint.gperf" +#line 352 "std-name-hint.gperf" {"recursive_mutex", "<mutex>", cxx11}, -#line 418 "../../src/gcc/cp/std-name-hint.gperf" +#line 418 "std-name-hint.gperf" {"basic_ispanstream", "<spanstream>", cxx23}, -#line 178 "../../src/gcc/cp/std-name-hint.gperf" +#line 178 "std-name-hint.gperf" {"format_to_n", "<format>", cxx20}, -#line 338 "../../src/gcc/cp/std-name-hint.gperf" +#line 338 "std-name-hint.gperf" {"pmr::memory_resource", "<memory_resource>", cxx17}, -#line 124 "../../src/gcc/cp/std-name-hint.gperf" +#line 124 "std-name-hint.gperf" {"equality_comparable_with", "<concepts>", cxx20}, -#line 493 "../../src/gcc/cp/std-name-hint.gperf" +#line 493 "std-name-hint.gperf" {"errc", "<system_error>", cxx11}, -#line 344 "../../src/gcc/cp/std-name-hint.gperf" +#line 344 "std-name-hint.gperf" {"pmr::synchronized_pool_resource", "<memory_resource>", cxx17}, -#line 385 "../../src/gcc/cp/std-name-hint.gperf" +#line 385 "std-name-hint.gperf" {"endl", "<ostream>", cxx98}, -#line 495 "../../src/gcc/cp/std-name-hint.gperf" +#line 495 "std-name-hint.gperf" {"error_code", "<system_error>", cxx11}, -#line 528 "../../src/gcc/cp/std-name-hint.gperf" +#line 528 "std-name-hint.gperf" {"enable_if_t", "<type_traits>", cxx14}, -#line 390 "../../src/gcc/cp/std-name-hint.gperf" +#line 390 "std-name-hint.gperf" {"ostream", "<ostream>", cxx98}, -#line 374 "../../src/gcc/cp/std-name-hint.gperf" +#line 374 "std-name-hint.gperf" {"numbers::log2e_v", "<numbers>", cxx20}, -#line 373 "../../src/gcc/cp/std-name-hint.gperf" +#line 373 "std-name-hint.gperf" {"numbers::log10e_v", "<numbers>", cxx20}, -#line 364 "../../src/gcc/cp/std-name-hint.gperf" +#line 364 "std-name-hint.gperf" {"nothrow_t", "<new>", cxx98}, -#line 512 "../../src/gcc/cp/std-name-hint.gperf" +#line 512 "std-name-hint.gperf" {"ignore", "<tuple>", cxx11}, -#line 360 "../../src/gcc/cp/std-name-hint.gperf" +#line 360 "std-name-hint.gperf" {"hardware_constructive_interference_size", "<new>", cxx17}, -#line 396 "../../src/gcc/cp/std-name-hint.gperf" +#line 396 "std-name-hint.gperf" {"priority_queue", "<queue>", cxx98}, -#line 424 "../../src/gcc/cp/std-name-hint.gperf" +#line 424 "std-name-hint.gperf" {"ospanstream", "<spanstream>", cxx23}, -#line 316 "../../src/gcc/cp/std-name-hint.gperf" +#line 316 "std-name-hint.gperf" {"enable_shared_from_this", "<memory>", cxx11}, -#line 265 "../../src/gcc/cp/std-name-hint.gperf" +#line 265 "std-name-hint.gperf" {"cout", "<iostream>", cxx98}, -#line 552 "../../src/gcc/cp/std-name-hint.gperf" +#line 552 "std-name-hint.gperf" {"cmp_greater", "<utility>", cxx20}, -#line 490 "../../src/gcc/cp/std-name-hint.gperf" +#line 490 "std-name-hint.gperf" {"basic_string_view", "<string_view>", cxx17}, -#line 249 "../../src/gcc/cp/std-name-hint.gperf" +#line 249 "std-name-hint.gperf" {"noskipws", "<ios>", cxx98}, -#line 177 "../../src/gcc/cp/std-name-hint.gperf" +#line 177 "std-name-hint.gperf" {"format_to", "<format>", cxx20}, -#line 502 "../../src/gcc/cp/std-name-hint.gperf" +#line 502 "std-name-hint.gperf" {"make_error_code", "<system_error>", cxx11}, -#line 174 "../../src/gcc/cp/std-name-hint.gperf" +#line 174 "std-name-hint.gperf" {"format_error", "<format>", cxx20}, -#line 347 "../../src/gcc/cp/std-name-hint.gperf" +#line 347 "std-name-hint.gperf" {"call_once", "<mutex>", cxx11}, -#line 377 "../../src/gcc/cp/std-name-hint.gperf" +#line 377 "std-name-hint.gperf" {"numbers::sqrt2_v", "<numbers>", cxx20}, -#line 378 "../../src/gcc/cp/std-name-hint.gperf" +#line 378 "std-name-hint.gperf" {"numbers::sqrt3_v", "<numbers>", cxx20}, -#line 242 "../../src/gcc/cp/std-name-hint.gperf" +#line 242 "std-name-hint.gperf" {"hexfloat", "<ios>", cxx11}, -#line 326 "../../src/gcc/cp/std-name-hint.gperf" +#line 326 "std-name-hint.gperf" {"shared_ptr", "<memory>", cxx11}, -#line 569 "../../src/gcc/cp/std-name-hint.gperf" +#line 569 "std-name-hint.gperf" {"integer_sequence", "<utility>", cxx14}, -#line 271 "../../src/gcc/cp/std-name-hint.gperf" +#line 271 "std-name-hint.gperf" {"istream", "<istream>", cxx98}, -#line 376 "../../src/gcc/cp/std-name-hint.gperf" +#line 376 "std-name-hint.gperf" {"numbers::pi_v", "<numbers>", cxx20}, -#line 259 "../../src/gcc/cp/std-name-hint.gperf" +#line 259 "std-name-hint.gperf" {"unitbuf", "<ios>", cxx98}, -#line 294 "../../src/gcc/cp/std-name-hint.gperf" +#line 294 "std-name-hint.gperf" {"list", "<list>", cxx98}, -#line 554 "../../src/gcc/cp/std-name-hint.gperf" +#line 554 "std-name-hint.gperf" {"cmp_less", "<utility>", cxx20}, -#line 422 "../../src/gcc/cp/std-name-hint.gperf" +#line 422 "std-name-hint.gperf" {"ispanstream", "<spanstream>", cxx23}, -#line 423 "../../src/gcc/cp/std-name-hint.gperf" +#line 423 "std-name-hint.gperf" {"ispanstream", "<spanstream>", cxx23}, -#line 470 "../../src/gcc/cp/std-name-hint.gperf" +#line 470 "std-name-hint.gperf" {"wstreambuf", "<streambuf>", cxx98}, -#line 432 "../../src/gcc/cp/std-name-hint.gperf" +#line 432 "std-name-hint.gperf" {"basic_ostringstream", "<sstream>", cxx98}, -#line 503 "../../src/gcc/cp/std-name-hint.gperf" +#line 503 "std-name-hint.gperf" {"make_error_condition", "<system_error>", cxx11}, -#line 570 "../../src/gcc/cp/std-name-hint.gperf" +#line 570 "std-name-hint.gperf" {"make_index_sequence", "<utility>", cxx14}, -#line 405 "../../src/gcc/cp/std-name-hint.gperf" +#line 405 "std-name-hint.gperf" {"counting_semaphore", "<semaphore>", cxx20}, -#line 355 "../../src/gcc/cp/std-name-hint.gperf" +#line 355 "std-name-hint.gperf" {"timed_mutex", "<mutex>", cxx11}, -#line 297 "../../src/gcc/cp/std-name-hint.gperf" +#line 297 "std-name-hint.gperf" {"multimap", "<map>", cxx98}, -#line 227 "../../src/gcc/cp/std-name-hint.gperf" +#line 227 "std-name-hint.gperf" {"put_money", "<iomanip>", cxx11}, -#line 309 "../../src/gcc/cp/std-name-hint.gperf" +#line 309 "std-name-hint.gperf" {"const_pointer_cast", "<memory>", cxx11}, -#line 45 "../../src/gcc/cp/std-name-hint.gperf" +#line 45 "std-name-hint.gperf" {"make_any", "<any>", cxx17}, -#line 465 "../../src/gcc/cp/std-name-hint.gperf" +#line 465 "std-name-hint.gperf" {"stop_source", "<stop_token>", cxx20}, -#line 548 "../../src/gcc/cp/std-name-hint.gperf" +#line 548 "std-name-hint.gperf" {"unordered_set", "<unordered_set>", cxx11}, -#line 582 "../../src/gcc/cp/std-name-hint.gperf" +#line 582 "std-name-hint.gperf" {"holds_alternative", "<variant>", cxx17}, -#line 514 "../../src/gcc/cp/std-name-hint.gperf" +#line 514 "std-name-hint.gperf" {"make_tuple", "<tuple>", cxx11}, -#line 47 "../../src/gcc/cp/std-name-hint.gperf" +#line 47 "std-name-hint.gperf" {"array", "<array>", cxx11}, -#line 517 "../../src/gcc/cp/std-name-hint.gperf" +#line 517 "std-name-hint.gperf" {"tuple_cat", "<tuple>", cxx11}, -#line 323 "../../src/gcc/cp/std-name-hint.gperf" +#line 323 "std-name-hint.gperf" {"owner_less", "<memory>", cxx11}, -#line 158 "../../src/gcc/cp/std-name-hint.gperf" +#line 158 "std-name-hint.gperf" {"exception", "<exception>", cxx98}, -#line 159 "../../src/gcc/cp/std-name-hint.gperf" +#line 159 "std-name-hint.gperf" {"exception_ptr", "<exception>", cxx11}, -#line 207 "../../src/gcc/cp/std-name-hint.gperf" +#line 207 "std-name-hint.gperf" {"hash", "<functional>", cxx11}, -#line 521 "../../src/gcc/cp/std-name-hint.gperf" +#line 521 "std-name-hint.gperf" {"tuple_size_v", "<tuple>", cxx17}, -#line 431 "../../src/gcc/cp/std-name-hint.gperf" +#line 431 "std-name-hint.gperf" {"basic_istringstream", "<sstream>", cxx98}, -#line 153 "../../src/gcc/cp/std-name-hint.gperf" +#line 153 "std-name-hint.gperf" {"uintptr_t", "<cstdint>", cxx11}, -#line 476 "../../src/gcc/cp/std-name-hint.gperf" +#line 476 "std-name-hint.gperf" {"stoi", "<string>", cxx11}, -#line 466 "../../src/gcc/cp/std-name-hint.gperf" +#line 466 "std-name-hint.gperf" {"stop_token", "<stop_token>", cxx20}, -#line 151 "../../src/gcc/cp/std-name-hint.gperf" +#line 151 "std-name-hint.gperf" {"uint_least8_t", "<cstdint>", cxx11}, -#line 380 "../../src/gcc/cp/std-name-hint.gperf" +#line 380 "std-name-hint.gperf" {"make_optional", "<optional>", cxx17}, -#line 345 "../../src/gcc/cp/std-name-hint.gperf" +#line 345 "std-name-hint.gperf" {"pmr::unsynchronized_pool_resource", "<memory_resource>", cxx17}, -#line 48 "../../src/gcc/cp/std-name-hint.gperf" +#line 48 "std-name-hint.gperf" {"to_array", "<array>", cxx20}, -#line 104 "../../src/gcc/cp/std-name-hint.gperf" +#line 104 "std-name-hint.gperf" {"complex_literals", "<complex>", cxx14}, -#line 411 "../../src/gcc/cp/std-name-hint.gperf" +#line 411 "std-name-hint.gperf" {"shared_mutex", "<shared_mutex>", cxx17}, -#line 375 "../../src/gcc/cp/std-name-hint.gperf" +#line 375 "std-name-hint.gperf" {"numbers::phi_v", "<numbers>", cxx20}, -#line 499 "../../src/gcc/cp/std-name-hint.gperf" +#line 499 "std-name-hint.gperf" {"is_error_code_enum_v", "<system_error>", cxx17}, -#line 155 "../../src/gcc/cp/std-name-hint.gperf" +#line 155 "std-name-hint.gperf" {"deque", "<deque>", cxx98}, -#line 412 "../../src/gcc/cp/std-name-hint.gperf" +#line 412 "std-name-hint.gperf" {"shared_timed_mutex", "<shared_mutex>", cxx14}, -#line 290 "../../src/gcc/cp/std-name-hint.gperf" +#line 290 "std-name-hint.gperf" {"ostreambuf_iterator", "<iterator>", cxx98}, -#line 501 "../../src/gcc/cp/std-name-hint.gperf" +#line 501 "std-name-hint.gperf" {"is_error_condition_enum_v", "<system_error>", cxx17}, -#line 148 "../../src/gcc/cp/std-name-hint.gperf" +#line 148 "std-name-hint.gperf" {"uint_least16_t", "<cstdint>", cxx11}, -#line 305 "../../src/gcc/cp/std-name-hint.gperf" +#line 305 "std-name-hint.gperf" {"allocator_arg_t", "<memory>", cxx11}, -#line 366 "../../src/gcc/cp/std-name-hint.gperf" +#line 366 "std-name-hint.gperf" {"numbers::e_v", "<numbers>", cxx20}, -#line 209 "../../src/gcc/cp/std-name-hint.gperf" +#line 209 "std-name-hint.gperf" {"invoke_r", "<functional>", cxx23}, -#line 441 "../../src/gcc/cp/std-name-hint.gperf" +#line 441 "std-name-hint.gperf" {"wostringstream", "<sstream>", cxx98}, -#line 122 "../../src/gcc/cp/std-name-hint.gperf" +#line 122 "std-name-hint.gperf" {"copy_constructible", "<concepts>", cxx20}, -#line 149 "../../src/gcc/cp/std-name-hint.gperf" +#line 149 "std-name-hint.gperf" {"uint_least32_t", "<cstdint>", cxx11}, -#line 108 "../../src/gcc/cp/std-name-hint.gperf" +#line 108 "std-name-hint.gperf" {"convertible_to", "<concepts>", cxx20}, -#line 234 "../../src/gcc/cp/std-name-hint.gperf" +#line 234 "std-name-hint.gperf" {"setprecision", "<iomanip>", cxx98}, -#line 498 "../../src/gcc/cp/std-name-hint.gperf" +#line 498 "std-name-hint.gperf" {"is_error_code_enum", "<system_error>", cxx11}, -#line 453 "../../src/gcc/cp/std-name-hint.gperf" +#line 453 "std-name-hint.gperf" {"overflow_error", "<stdexcept>", cxx98}, -#line 414 "../../src/gcc/cp/std-name-hint.gperf" +#line 414 "std-name-hint.gperf" {"source_location", "<source_location>", cxx20}, -#line 500 "../../src/gcc/cp/std-name-hint.gperf" +#line 500 "std-name-hint.gperf" {"is_error_condition_enum", "<system_error>", cxx11}, -#line 400 "../../src/gcc/cp/std-name-hint.gperf" +#line 400 "std-name-hint.gperf" {"ranges::enable_view", "<ranges>", cxx20}, -#line 218 "../../src/gcc/cp/std-name-hint.gperf" +#line 218 "std-name-hint.gperf" {"async", "<future>", cxx11}, -#line 103 "../../src/gcc/cp/std-name-hint.gperf" +#line 103 "std-name-hint.gperf" {"complex", "<complex>", cxx98}, -#line 150 "../../src/gcc/cp/std-name-hint.gperf" +#line 150 "std-name-hint.gperf" {"uint_least64_t", "<cstdint>", cxx11}, -#line 232 "../../src/gcc/cp/std-name-hint.gperf" +#line 232 "std-name-hint.gperf" {"setfill", "<iomanip>", cxx98}, -#line 79 "../../src/gcc/cp/std-name-hint.gperf" +#line 79 "std-name-hint.gperf" {"chrono::parse", "<chrono>", cxx20}, -#line 285 "../../src/gcc/cp/std-name-hint.gperf" +#line 285 "std-name-hint.gperf" {"istreambuf_iterator", "<iterator>", cxx98}, -#line 473 "../../src/gcc/cp/std-name-hint.gperf" +#line 473 "std-name-hint.gperf" {"char_traits", "<string>", cxx98}, -#line 263 "../../src/gcc/cp/std-name-hint.gperf" +#line 263 "std-name-hint.gperf" {"cin", "<iostream>", cxx98}, -#line 61 "../../src/gcc/cp/std-name-hint.gperf" +#line 61 "std-name-hint.gperf" {"chrono::duration_cast", "<chrono>", cxx11}, -#line 152 "../../src/gcc/cp/std-name-hint.gperf" +#line 152 "std-name-hint.gperf" {"uintmax_t", "<cstdint>", cxx11}, -#line 43 "../../src/gcc/cp/std-name-hint.gperf" +#line 43 "std-name-hint.gperf" {"any", "<any>", cxx17}, -#line 389 "../../src/gcc/cp/std-name-hint.gperf" +#line 389 "std-name-hint.gperf" {"noemit_on_flush", "<ostream>", cxx20}, -#line 66 "../../src/gcc/cp/std-name-hint.gperf" +#line 66 "std-name-hint.gperf" {"chrono::get_tzdb_list", "<chrono>", cxx20}, -#line 93 "../../src/gcc/cp/std-name-hint.gperf" +#line 93 "std-name-hint.gperf" {"chrono::weeks", "<chrono>", cxx20}, -#line 65 "../../src/gcc/cp/std-name-hint.gperf" +#line 65 "std-name-hint.gperf" {"chrono::get_tzdb", "<chrono>", cxx20}, -#line 302 "../../src/gcc/cp/std-name-hint.gperf" +#line 302 "std-name-hint.gperf" {"allocate_shared_for_overwrite", "<memory>", cxx20}, -#line 547 "../../src/gcc/cp/std-name-hint.gperf" +#line 547 "std-name-hint.gperf" {"unordered_multiset", "<unordered_set>", cxx11}, -#line 194 "../../src/gcc/cp/std-name-hint.gperf" +#line 194 "std-name-hint.gperf" {"forward_list", "<forward_list>", cxx11}, -#line 496 "../../src/gcc/cp/std-name-hint.gperf" +#line 496 "std-name-hint.gperf" {"error_condition", "<system_error>", cxx11}, -#line 542 "../../src/gcc/cp/std-name-hint.gperf" +#line 542 "std-name-hint.gperf" {"bad_typeid", "<typeinfo>", cxx98}, -#line 60 "../../src/gcc/cp/std-name-hint.gperf" +#line 60 "std-name-hint.gperf" {"chrono::duration", "<chrono>", cxx11}, -#line 510 "../../src/gcc/cp/std-name-hint.gperf" +#line 510 "std-name-hint.gperf" {"apply", "<tuple>", cxx17}, -#line 95 "../../src/gcc/cp/std-name-hint.gperf" +#line 95 "std-name-hint.gperf" {"chrono::zoned_time", "<chrono>", cxx20}, -#line 477 "../../src/gcc/cp/std-name-hint.gperf" +#line 477 "std-name-hint.gperf" {"stol", "<string>", cxx11}, -#line 479 "../../src/gcc/cp/std-name-hint.gperf" +#line 479 "std-name-hint.gperf" {"stoll", "<string>", cxx11}, -#line 480 "../../src/gcc/cp/std-name-hint.gperf" +#line 480 "std-name-hint.gperf" {"stoul", "<string>", cxx11}, -#line 481 "../../src/gcc/cp/std-name-hint.gperf" +#line 481 "std-name-hint.gperf" {"stoull", "<string>", cxx11}, -#line 220 "../../src/gcc/cp/std-name-hint.gperf" +#line 220 "std-name-hint.gperf" {"packaged_task", "<future>", cxx11}, -#line 544 "../../src/gcc/cp/std-name-hint.gperf" +#line 544 "std-name-hint.gperf" {"unordered_map", "<unordered_map>", cxx11}, -#line 77 "../../src/gcc/cp/std-name-hint.gperf" +#line 77 "std-name-hint.gperf" {"chrono::months", "<chrono>", cxx20}, -#line 76 "../../src/gcc/cp/std-name-hint.gperf" +#line 76 "std-name-hint.gperf" {"chrono::minutes", "<chrono>", cxx11}, -#line 545 "../../src/gcc/cp/std-name-hint.gperf" +#line 545 "std-name-hint.gperf" {"unordered_multimap", "<unordered_map>", cxx11}, -#line 78 "../../src/gcc/cp/std-name-hint.gperf" +#line 78 "std-name-hint.gperf" {"chrono::nanoseconds", "<chrono>", cxx11}, -#line 286 "../../src/gcc/cp/std-name-hint.gperf" +#line 286 "std-name-hint.gperf" {"iterator_traits", "<iterator>", cxx98}, -#line 404 "../../src/gcc/cp/std-name-hint.gperf" +#line 404 "std-name-hint.gperf" {"binary_semaphore", "<semaphore>", cxx20}, -#line 281 "../../src/gcc/cp/std-name-hint.gperf" +#line 281 "std-name-hint.gperf" {"end", "<iterator>", cxx11}, -#line 429 "../../src/gcc/cp/std-name-hint.gperf" +#line 429 "std-name-hint.gperf" {"wspanbuf", "<spanstream>", cxx23}, -#line 252 "../../src/gcc/cp/std-name-hint.gperf" +#line 252 "std-name-hint.gperf" {"oct", "<ios>", cxx98}, -#line 245 "../../src/gcc/cp/std-name-hint.gperf" +#line 245 "std-name-hint.gperf" {"noboolalpha", "<ios>", cxx98}, -#line 450 "../../src/gcc/cp/std-name-hint.gperf" +#line 450 "std-name-hint.gperf" {"length_error", "<stdexcept>", cxx98}, -#line 560 "../../src/gcc/cp/std-name-hint.gperf" +#line 560 "std-name-hint.gperf" {"in_place", "<utility>", cxx17}, -#line 563 "../../src/gcc/cp/std-name-hint.gperf" +#line 563 "std-name-hint.gperf" {"in_place_t", "<utility>", cxx17}, -#line 384 "../../src/gcc/cp/std-name-hint.gperf" +#line 384 "std-name-hint.gperf" {"emit_on_flush", "<ostream>", cxx20}, -#line 440 "../../src/gcc/cp/std-name-hint.gperf" +#line 440 "std-name-hint.gperf" {"wistringstream", "<sstream>", cxx98}, -#line 327 "../../src/gcc/cp/std-name-hint.gperf" +#line 327 "std-name-hint.gperf" {"static_pointer_cast", "<memory>", cxx11}, -#line 260 "../../src/gcc/cp/std-name-hint.gperf" +#line 260 "std-name-hint.gperf" {"uppercase", "<ios>", cxx98}, -#line 277 "../../src/gcc/cp/std-name-hint.gperf" +#line 277 "std-name-hint.gperf" {"common_iterator", "<iterator>", cxx20}, -#line 117 "../../src/gcc/cp/std-name-hint.gperf" +#line 117 "std-name-hint.gperf" {"swappable_with", "<concepts>", cxx20}, -#line 359 "../../src/gcc/cp/std-name-hint.gperf" +#line 359 "std-name-hint.gperf" {"bad_alloc", "<new>", cxx98}, -#line 391 "../../src/gcc/cp/std-name-hint.gperf" +#line 391 "std-name-hint.gperf" {"wostream", "<ostream>", cxx98}, -#line 348 "../../src/gcc/cp/std-name-hint.gperf" +#line 348 "std-name-hint.gperf" {"lock", "<mutex>", cxx11}, -#line 504 "../../src/gcc/cp/std-name-hint.gperf" +#line 504 "std-name-hint.gperf" {"system_category", "<system_error>", cxx11}, -#line 128 "../../src/gcc/cp/std-name-hint.gperf" +#line 128 "std-name-hint.gperf" {"copyable", "<concepts>", cxx20}, -#line 139 "../../src/gcc/cp/std-name-hint.gperf" +#line 139 "std-name-hint.gperf" {"condition_variable", "<condition_variable>", cxx11}, -#line 240 "../../src/gcc/cp/std-name-hint.gperf" +#line 240 "std-name-hint.gperf" {"fixed", "<ios>", cxx98}, -#line 553 "../../src/gcc/cp/std-name-hint.gperf" +#line 553 "std-name-hint.gperf" {"cmp_greater_equal", "<utility>", cxx20}, -#line 508 "../../src/gcc/cp/std-name-hint.gperf" +#line 508 "std-name-hint.gperf" {"thread", "<thread>", cxx11}, -#line 439 "../../src/gcc/cp/std-name-hint.gperf" +#line 439 "std-name-hint.gperf" {"stringstream", "<sstream>", cxx98}, -#line 58 "../../src/gcc/cp/std-name-hint.gperf" +#line 58 "std-name-hint.gperf" {"chrono::clock_cast", "<chrono>", cxx20}, -#line 579 "../../src/gcc/cp/std-name-hint.gperf" +#line 579 "std-name-hint.gperf" {"unreachable", "<utility>", cxx23}, -#line 428 "../../src/gcc/cp/std-name-hint.gperf" +#line 428 "std-name-hint.gperf" {"wospanstream", "<spanstream>", cxx23}, -#line 330 "../../src/gcc/cp/std-name-hint.gperf" +#line 330 "std-name-hint.gperf" {"unique_ptr", "<memory>", cxx11}, -#line 562 "../../src/gcc/cp/std-name-hint.gperf" +#line 562 "std-name-hint.gperf" {"in_place_index_t", "<utility>", cxx17}, -#line 363 "../../src/gcc/cp/std-name-hint.gperf" +#line 363 "std-name-hint.gperf" {"nothrow", "<new>", cxx98}, -#line 64 "../../src/gcc/cp/std-name-hint.gperf" +#line 64 "std-name-hint.gperf" {"chrono::get_leap_second_info", "<chrono>", cxx20}, -#line 204 "../../src/gcc/cp/std-name-hint.gperf" +#line 204 "std-name-hint.gperf" {"bind", "<functional>", cxx11}, -#line 89 "../../src/gcc/cp/std-name-hint.gperf" +#line 89 "std-name-hint.gperf" {"chrono::time_zone", "<chrono>", cxx20}, -#line 120 "../../src/gcc/cp/std-name-hint.gperf" +#line 120 "std-name-hint.gperf" {"default_initializable", "<concepts>", cxx20}, -#line 145 "../../src/gcc/cp/std-name-hint.gperf" +#line 145 "std-name-hint.gperf" {"uint_fast32_t", "<cstdint>", cxx11}, -#line 87 "../../src/gcc/cp/std-name-hint.gperf" +#line 87 "std-name-hint.gperf" {"chrono::time_point", "<chrono>", cxx11}, -#line 444 "../../src/gcc/cp/std-name-hint.gperf" +#line 444 "std-name-hint.gperf" {"stack", "<stack>", cxx98}, -#line 215 "../../src/gcc/cp/std-name-hint.gperf" +#line 215 "std-name-hint.gperf" {"unwrap_reference", "<functional>", cxx20}, -#line 88 "../../src/gcc/cp/std-name-hint.gperf" +#line 88 "std-name-hint.gperf" {"chrono::time_point_cast", "<chrono>", cxx11}, -#line 223 "../../src/gcc/cp/std-name-hint.gperf" +#line 223 "std-name-hint.gperf" {"generator", "<generator>", cxx23}, -#line 216 "../../src/gcc/cp/std-name-hint.gperf" +#line 216 "std-name-hint.gperf" {"unwrap_reference_t", "<functional>", cxx20}, -#line 382 "../../src/gcc/cp/std-name-hint.gperf" +#line 382 "std-name-hint.gperf" {"optional", "<optional>", cxx17}, -#line 112 "../../src/gcc/cp/std-name-hint.gperf" +#line 112 "std-name-hint.gperf" {"signed_integral", "<concepts>", cxx20}, -#line 456 "../../src/gcc/cp/std-name-hint.gperf" +#line 456 "std-name-hint.gperf" {"underflow_error", "<stdexcept>", cxx98}, -#line 239 "../../src/gcc/cp/std-name-hint.gperf" +#line 239 "std-name-hint.gperf" {"defaultfloat", "<ios>", cxx11}, -#line 146 "../../src/gcc/cp/std-name-hint.gperf" +#line 146 "std-name-hint.gperf" {"uint_fast64_t", "<cstdint>", cxx11}, -#line 129 "../../src/gcc/cp/std-name-hint.gperf" +#line 129 "std-name-hint.gperf" {"semiregular", "<concepts>", cxx20}, -#line 111 "../../src/gcc/cp/std-name-hint.gperf" +#line 111 "std-name-hint.gperf" {"integral", "<concepts>", cxx20}, -#line 243 "../../src/gcc/cp/std-name-hint.gperf" +#line 243 "std-name-hint.gperf" {"internal", "<ios>", cxx98}, -#line 144 "../../src/gcc/cp/std-name-hint.gperf" +#line 144 "std-name-hint.gperf" {"uint_fast16_t", "<cstdint>", cxx11}, -#line 329 "../../src/gcc/cp/std-name-hint.gperf" +#line 329 "std-name-hint.gperf" {"uninitialized_construct_using_allocator", "<memory>", cxx20}, -#line 81 "../../src/gcc/cp/std-name-hint.gperf" +#line 81 "std-name-hint.gperf" {"chrono::remote_version", "<chrono>", cxx20}, -#line 458 "../../src/gcc/cp/std-name-hint.gperf" +#line 458 "std-name-hint.gperf" {"bfloat16_t", "<stdfloat>", cxx23}, -#line 576 "../../src/gcc/cp/std-name-hint.gperf" +#line 576 "std-name-hint.gperf" {"piecewise_construct", "<utility>", cxx11}, -#line 577 "../../src/gcc/cp/std-name-hint.gperf" +#line 577 "std-name-hint.gperf" {"piecewise_construct_t", "<utility>", cxx11}, -#line 278 "../../src/gcc/cp/std-name-hint.gperf" +#line 278 "std-name-hint.gperf" {"const_iterator", "<iterator>", cxx23}, -#line 484 "../../src/gcc/cp/std-name-hint.gperf" +#line 484 "std-name-hint.gperf" {"to_wstring", "<string>", cxx17}, -#line 356 "../../src/gcc/cp/std-name-hint.gperf" +#line 356 "std-name-hint.gperf" {"try_lock", "<mutex>", cxx11}, -#line 561 "../../src/gcc/cp/std-name-hint.gperf" +#line 561 "std-name-hint.gperf" {"in_place_index", "<utility>", cxx17}, -#line 51 "../../src/gcc/cp/std-name-hint.gperf" +#line 51 "std-name-hint.gperf" {"atomic_ref", "<atomic>", cxx20}, -#line 113 "../../src/gcc/cp/std-name-hint.gperf" +#line 113 "std-name-hint.gperf" {"unsigned_integral", "<concepts>", cxx20}, -#line 94 "../../src/gcc/cp/std-name-hint.gperf" +#line 94 "std-name-hint.gperf" {"chrono::years", "<chrono>", cxx20}, -#line 229 "../../src/gcc/cp/std-name-hint.gperf" +#line 229 "std-name-hint.gperf" {"quoted", "<iomanip>", cxx14}, -#line 115 "../../src/gcc/cp/std-name-hint.gperf" +#line 115 "std-name-hint.gperf" {"assignable_from", "<concepts>", cxx20}, -#line 53 "../../src/gcc/cp/std-name-hint.gperf" +#line 53 "std-name-hint.gperf" {"atomic_uintmax_t", "<atomic>", cxx20}, -#line 162 "../../src/gcc/cp/std-name-hint.gperf" +#line 162 "std-name-hint.gperf" {"uncaught_exceptions", "<exception>", cxx17}, -#line 331 "../../src/gcc/cp/std-name-hint.gperf" +#line 331 "std-name-hint.gperf" {"uses_allocator", "<memory>", cxx11}, -#line 472 "../../src/gcc/cp/std-name-hint.gperf" +#line 472 "std-name-hint.gperf" {"basic_string", "<string>", cxx98}, -#line 311 "../../src/gcc/cp/std-name-hint.gperf" +#line 311 "std-name-hint.gperf" {"default_delete", "<memory>", cxx11}, -#line 164 "../../src/gcc/cp/std-name-hint.gperf" +#line 164 "std-name-hint.gperf" {"expected", "<expected>", cxx23}, -#line 313 "../../src/gcc/cp/std-name-hint.gperf" +#line 313 "std-name-hint.gperf" {"destroy_at", "<memory>", cxx20}, -#line 536 "../../src/gcc/cp/std-name-hint.gperf" +#line 536 "std-name-hint.gperf" {"type_identity_t", "<type_traits>", cxx20}, -#line 63 "../../src/gcc/cp/std-name-hint.gperf" +#line 63 "std-name-hint.gperf" {"chrono::from_stream", "<chrono>", cxx20}, -#line 427 "../../src/gcc/cp/std-name-hint.gperf" +#line 427 "std-name-hint.gperf" {"wispanstream", "<spanstream>", cxx23}, -#line 52 "../../src/gcc/cp/std-name-hint.gperf" +#line 52 "std-name-hint.gperf" {"atomic_signed_lock_free", "<atomic>", cxx11}, -#line 266 "../../src/gcc/cp/std-name-hint.gperf" +#line 266 "std-name-hint.gperf" {"wcerr", "<iostream>", cxx98}, -#line 511 "../../src/gcc/cp/std-name-hint.gperf" +#line 511 "std-name-hint.gperf" {"forward_as_tuple", "<tuple>", cxx11}, -#line 187 "../../src/gcc/cp/std-name-hint.gperf" +#line 187 "std-name-hint.gperf" {"vformat", "<format>", cxx20}, -#line 332 "../../src/gcc/cp/std-name-hint.gperf" +#line 332 "std-name-hint.gperf" {"uses_allocator_construction_args", "<memory>", cxx20}, -#line 269 "../../src/gcc/cp/std-name-hint.gperf" +#line 269 "std-name-hint.gperf" {"wcout", "<iostream>", cxx98}, -#line 314 "../../src/gcc/cp/std-name-hint.gperf" +#line 314 "std-name-hint.gperf" {"destroy_n", "<memory>", cxx20}, -#line 226 "../../src/gcc/cp/std-name-hint.gperf" +#line 226 "std-name-hint.gperf" {"get_time", "<iomanip>", cxx11}, -#line 555 "../../src/gcc/cp/std-name-hint.gperf" +#line 555 "std-name-hint.gperf" {"cmp_less_equal", "<utility>", cxx20}, -#line 80 "../../src/gcc/cp/std-name-hint.gperf" +#line 80 "std-name-hint.gperf" {"chrono::reload_tzdb", "<chrono>", cxx20}, -#line 523 "../../src/gcc/cp/std-name-hint.gperf" +#line 523 "std-name-hint.gperf" {"conjunction", "<type_traits>", cxx17}, -#line 75 "../../src/gcc/cp/std-name-hint.gperf" +#line 75 "std-name-hint.gperf" {"chrono::milliseconds", "<chrono>", cxx11}, -#line 59 "../../src/gcc/cp/std-name-hint.gperf" +#line 59 "std-name-hint.gperf" {"chrono::days", "<chrono>", cxx20}, -#line 474 "../../src/gcc/cp/std-name-hint.gperf" +#line 474 "std-name-hint.gperf" {"stod", "<string>", cxx11}, -#line 478 "../../src/gcc/cp/std-name-hint.gperf" +#line 478 "std-name-hint.gperf" {"stold", "<string>", cxx11}, -#line 267 "../../src/gcc/cp/std-name-hint.gperf" +#line 267 "std-name-hint.gperf" {"wcin", "<iostream>", cxx98}, -#line 529 "../../src/gcc/cp/std-name-hint.gperf" +#line 529 "std-name-hint.gperf" {"invoke_result", "<type_traits>", cxx17}, -#line 530 "../../src/gcc/cp/std-name-hint.gperf" +#line 530 "std-name-hint.gperf" {"invoke_result_t", "<type_traits>", cxx17}, -#line 50 "../../src/gcc/cp/std-name-hint.gperf" +#line 50 "std-name-hint.gperf" {"atomic", "<atomic>", cxx11}, -#line 71 "../../src/gcc/cp/std-name-hint.gperf" +#line 71 "std-name-hint.gperf" {"chrono::leap_second_info", "<chrono>", cxx20}, -#line 238 "../../src/gcc/cp/std-name-hint.gperf" +#line 238 "std-name-hint.gperf" {"dec", "<ios>", cxx98}, -#line 157 "../../src/gcc/cp/std-name-hint.gperf" +#line 157 "std-name-hint.gperf" {"current_exception", "<exception>", cxx11}, -#line 119 "../../src/gcc/cp/std-name-hint.gperf" +#line 119 "std-name-hint.gperf" {"constructible_from", "<concepts>", cxx20}, -#line 100 "../../src/gcc/cp/std-name-hint.gperf" +#line 100 "std-name-hint.gperf" {"weak_equality", "<compare>", cxx20}, -#line 333 "../../src/gcc/cp/std-name-hint.gperf" +#line 333 "std-name-hint.gperf" {"uses_allocator_v", "<memory>", cxx17}, -#line 69 "../../src/gcc/cp/std-name-hint.gperf" +#line 69 "std-name-hint.gperf" {"chrono::hours", "<chrono>", cxx11}, -#line 109 "../../src/gcc/cp/std-name-hint.gperf" +#line 109 "std-name-hint.gperf" {"common_reference_with", "<concepts>", cxx20}, -#line 483 "../../src/gcc/cp/std-name-hint.gperf" +#line 483 "std-name-hint.gperf" {"to_string", "<string>", cxx17}, -#line 524 "../../src/gcc/cp/std-name-hint.gperf" +#line 524 "std-name-hint.gperf" {"conjunction_v", "<type_traits>", cxx17}, -#line 578 "../../src/gcc/cp/std-name-hint.gperf" +#line 578 "std-name-hint.gperf" {"to_underlying", "<utility>", cxx23}, -#line 402 "../../src/gcc/cp/std-name-hint.gperf" +#line 402 "std-name-hint.gperf" {"scoped_allocator_adaptor", "<scoped_allocator>", cxx11}, -#line 310 "../../src/gcc/cp/std-name-hint.gperf" +#line 310 "std-name-hint.gperf" {"construct_at", "<memory>", cxx20}, -#line 564 "../../src/gcc/cp/std-name-hint.gperf" +#line 564 "std-name-hint.gperf" {"in_place_type", "<utility>", cxx17}, -#line 320 "../../src/gcc/cp/std-name-hint.gperf" +#line 320 "std-name-hint.gperf" {"make_shared_for_overwrite", "<memory>", cxx20}, -#line 166 "../../src/gcc/cp/std-name-hint.gperf" +#line 166 "std-name-hint.gperf" {"basic_format_arg", "<format>", cxx20}, -#line 73 "../../src/gcc/cp/std-name-hint.gperf" +#line 73 "std-name-hint.gperf" {"chrono::locate_zone", "<chrono>", cxx20}, -#line 72 "../../src/gcc/cp/std-name-hint.gperf" +#line 72 "std-name-hint.gperf" {"chrono::local_t", "<chrono>", cxx20}, -#line 170 "../../src/gcc/cp/std-name-hint.gperf" +#line 170 "std-name-hint.gperf" {"basic_format_string", "<format>", cxx20}, -#line 565 "../../src/gcc/cp/std-name-hint.gperf" +#line 565 "std-name-hint.gperf" {"in_place_type_t", "<utility>", cxx17}, -#line 279 "../../src/gcc/cp/std-name-hint.gperf" +#line 279 "std-name-hint.gperf" {"counted_iterator", "<iterator>", cxx20}, -#line 448 "../../src/gcc/cp/std-name-hint.gperf" +#line 448 "std-name-hint.gperf" {"domain_error", "<stdexcept>", cxx98}, -#line 84 "../../src/gcc/cp/std-name-hint.gperf" +#line 84 "std-name-hint.gperf" {"chrono::steady_clock", "<chrono>", cxx11}, -#line 188 "../../src/gcc/cp/std-name-hint.gperf" +#line 188 "std-name-hint.gperf" {"vformat_to", "<format>", cxx20}, -#line 54 "../../src/gcc/cp/std-name-hint.gperf" +#line 54 "std-name-hint.gperf" {"atomic_unsigned_lock_free", "<atomic>", cxx11}, -#line 147 "../../src/gcc/cp/std-name-hint.gperf" +#line 147 "std-name-hint.gperf" {"uint_fast8_t", "<cstdint>", cxx11}, -#line 83 "../../src/gcc/cp/std-name-hint.gperf" +#line 83 "std-name-hint.gperf" {"chrono::seconds", "<chrono>", cxx11}, -#line 74 "../../src/gcc/cp/std-name-hint.gperf" +#line 74 "std-name-hint.gperf" {"chrono::microseconds", "<chrono>", cxx11}, -#line 67 "../../src/gcc/cp/std-name-hint.gperf" +#line 67 "std-name-hint.gperf" {"chrono::gps_clock", "<chrono>", cxx20}, -#line 85 "../../src/gcc/cp/std-name-hint.gperf" +#line 85 "std-name-hint.gperf" {"chrono::system_clock", "<chrono>", cxx11}, -#line 140 "../../src/gcc/cp/std-name-hint.gperf" +#line 140 "std-name-hint.gperf" {"condition_variable_any", "<condition_variable>", cxx11}, -#line 214 "../../src/gcc/cp/std-name-hint.gperf" +#line 214 "std-name-hint.gperf" {"unwrap_ref_decay_t", "<functional>", cxx20}, -#line 136 "../../src/gcc/cp/std-name-hint.gperf" +#line 136 "std-name-hint.gperf" {"strict_weak_order", "<concepts>", cxx20}, -#line 437 "../../src/gcc/cp/std-name-hint.gperf" +#line 437 "std-name-hint.gperf" {"ostringstream", "<sstream>", cxx98}, -#line 317 "../../src/gcc/cp/std-name-hint.gperf" +#line 317 "std-name-hint.gperf" {"get_deleter", "<memory>", cxx11}, -#line 367 "../../src/gcc/cp/std-name-hint.gperf" +#line 367 "std-name-hint.gperf" {"numbers::egamma_v", "<numbers>", cxx20}, -#line 566 "../../src/gcc/cp/std-name-hint.gperf" +#line 566 "std-name-hint.gperf" {"in_range", "<utility>", cxx20}, -#line 558 "../../src/gcc/cp/std-name-hint.gperf" +#line 558 "std-name-hint.gperf" {"exchange", "<utility>", cxx14}, -#line 551 "../../src/gcc/cp/std-name-hint.gperf" +#line 551 "std-name-hint.gperf" {"cmp_equal", "<utility>", cxx20}, -#line 556 "../../src/gcc/cp/std-name-hint.gperf" +#line 556 "std-name-hint.gperf" {"cmp_not_equal", "<utility>", cxx20}, -#line 435 "../../src/gcc/cp/std-name-hint.gperf" +#line 435 "std-name-hint.gperf" {"istringstream", "<sstream>", cxx98}, -#line 436 "../../src/gcc/cp/std-name-hint.gperf" +#line 436 "std-name-hint.gperf" {"istringstream", "<sstream>", cxx98}, -#line 442 "../../src/gcc/cp/std-name-hint.gperf" +#line 442 "std-name-hint.gperf" {"wstringbuf", "<sstream>", cxx98}, -#line 225 "../../src/gcc/cp/std-name-hint.gperf" +#line 225 "std-name-hint.gperf" {"get_money", "<iomanip>", cxx11}, -#line 191 "../../src/gcc/cp/std-name-hint.gperf" +#line 191 "std-name-hint.gperf" {"wformat_parse_context", "<format>", cxx20}, -#line 482 "../../src/gcc/cp/std-name-hint.gperf" +#line 482 "std-name-hint.gperf" {"string", "<string>", cxx98}, -#line 280 "../../src/gcc/cp/std-name-hint.gperf" +#line 280 "std-name-hint.gperf" {"distance", "<iterator>", cxx98}, -#line 557 "../../src/gcc/cp/std-name-hint.gperf" +#line 557 "std-name-hint.gperf" {"declval", "<utility>", cxx11}, -#line 254 "../../src/gcc/cp/std-name-hint.gperf" +#line 254 "std-name-hint.gperf" {"scientific", "<ios>", cxx98}, -#line 98 "../../src/gcc/cp/std-name-hint.gperf" +#line 98 "std-name-hint.gperf" {"strong_equality", "<compare>", cxx20}, -#line 487 "../../src/gcc/cp/std-name-hint.gperf" +#line 487 "std-name-hint.gperf" {"u8string", "<string>", cxx20}, -#line 190 "../../src/gcc/cp/std-name-hint.gperf" +#line 190 "std-name-hint.gperf" {"wformat_context", "<format>", cxx20}, -#line 312 "../../src/gcc/cp/std-name-hint.gperf" +#line 312 "std-name-hint.gperf" {"destroy", "<memory>", cxx20}, -#line 559 "../../src/gcc/cp/std-name-hint.gperf" +#line 559 "std-name-hint.gperf" {"forward", "<utility>", cxx11}, -#line 535 "../../src/gcc/cp/std-name-hint.gperf" +#line 535 "std-name-hint.gperf" {"type_identity", "<type_traits>", cxx20}, -#line 464 "../../src/gcc/cp/std-name-hint.gperf" +#line 464 "std-name-hint.gperf" {"stop_callback", "<stop_token>", cxx20}, -#line 86 "../../src/gcc/cp/std-name-hint.gperf" +#line 86 "std-name-hint.gperf" {"chrono::tai_clock", "<chrono>", cxx20}, -#line 91 "../../src/gcc/cp/std-name-hint.gperf" +#line 91 "std-name-hint.gperf" {"chrono::tzdb_list", "<chrono>", cxx20}, -#line 301 "../../src/gcc/cp/std-name-hint.gperf" +#line 301 "std-name-hint.gperf" {"allocate_shared", "<memory>", cxx11}, -#line 90 "../../src/gcc/cp/std-name-hint.gperf" +#line 90 "std-name-hint.gperf" {"chrono::tzdb", "<chrono>", cxx20}, -#line 126 "../../src/gcc/cp/std-name-hint.gperf" +#line 126 "std-name-hint.gperf" {"totally_ordered_with", "<concepts>", cxx20}, -#line 525 "../../src/gcc/cp/std-name-hint.gperf" +#line 525 "std-name-hint.gperf" {"disjunction", "<type_traits>", cxx17}, -#line 110 "../../src/gcc/cp/std-name-hint.gperf" +#line 110 "std-name-hint.gperf" {"common_with", "<concepts>", cxx20}, -#line 202 "../../src/gcc/cp/std-name-hint.gperf" +#line 202 "std-name-hint.gperf" {"ofstream", "<fstream>", cxx98}, -#line 349 "../../src/gcc/cp/std-name-hint.gperf" +#line 349 "std-name-hint.gperf" {"lock_guard", "<mutex>", cxx11}, -#line 118 "../../src/gcc/cp/std-name-hint.gperf" +#line 118 "std-name-hint.gperf" {"destructible", "<concepts>", cxx20}, -#line 176 "../../src/gcc/cp/std-name-hint.gperf" +#line 176 "std-name-hint.gperf" {"format_string", "<format>", cxx20}, -#line 410 "../../src/gcc/cp/std-name-hint.gperf" +#line 410 "std-name-hint.gperf" {"shared_lock", "<shared_mutex>", cxx14}, -#line 315 "../../src/gcc/cp/std-name-hint.gperf" +#line 315 "std-name-hint.gperf" {"dynamic_pointer_cast", "<memory>", cxx11}, -#line 101 "../../src/gcc/cp/std-name-hint.gperf" +#line 101 "std-name-hint.gperf" {"weak_ordering", "<compare>", cxx20}, -#line 201 "../../src/gcc/cp/std-name-hint.gperf" +#line 201 "std-name-hint.gperf" {"ifstream", "<fstream>", cxx98}, -#line 452 "../../src/gcc/cp/std-name-hint.gperf" +#line 452 "std-name-hint.gperf" {"out_of_range", "<stdexcept>", cxx98}, -#line 264 "../../src/gcc/cp/std-name-hint.gperf" +#line 264 "std-name-hint.gperf" {"clog", "<iostream>", cxx98}, -#line 62 "../../src/gcc/cp/std-name-hint.gperf" +#line 62 "std-name-hint.gperf" {"chrono::file_clock", "<chrono>", cxx20}, -#line 526 "../../src/gcc/cp/std-name-hint.gperf" +#line 526 "std-name-hint.gperf" {"disjunction_v", "<type_traits>", cxx17}, -#line 485 "../../src/gcc/cp/std-name-hint.gperf" +#line 485 "std-name-hint.gperf" {"u16string", "<string>", cxx11}, -#line 351 "../../src/gcc/cp/std-name-hint.gperf" +#line 351 "std-name-hint.gperf" {"once_flag", "<mutex>", cxx11}, -#line 491 "../../src/gcc/cp/std-name-hint.gperf" +#line 491 "std-name-hint.gperf" {"string_view", "<string_view>", cxx17}, -#line 304 "../../src/gcc/cp/std-name-hint.gperf" +#line 304 "std-name-hint.gperf" {"allocator_arg", "<memory>", cxx11}, -#line 486 "../../src/gcc/cp/std-name-hint.gperf" +#line 486 "std-name-hint.gperf" {"u32string", "<string>", cxx11}, -#line 213 "../../src/gcc/cp/std-name-hint.gperf" +#line 213 "std-name-hint.gperf" {"unwrap_ref_decay", "<functional>", cxx20}, -#line 70 "../../src/gcc/cp/std-name-hint.gperf" +#line 70 "std-name-hint.gperf" {"chrono::leap_second", "<chrono>", cxx20}, -#line 92 "../../src/gcc/cp/std-name-hint.gperf" +#line 92 "std-name-hint.gperf" {"chrono::utc_clock", "<chrono>", cxx20}, -#line 107 "../../src/gcc/cp/std-name-hint.gperf" +#line 107 "std-name-hint.gperf" {"derived_from", "<concepts>", cxx20}, -#line 99 "../../src/gcc/cp/std-name-hint.gperf" +#line 99 "std-name-hint.gperf" {"strong_ordering", "<compare>", cxx20}, -#line 497 "../../src/gcc/cp/std-name-hint.gperf" +#line 497 "std-name-hint.gperf" {"generic_category", "<system_error>", cxx11}, -#line 125 "../../src/gcc/cp/std-name-hint.gperf" +#line 125 "std-name-hint.gperf" {"totally_ordered", "<concepts>", cxx20}, -#line 494 "../../src/gcc/cp/std-name-hint.gperf" +#line 494 "std-name-hint.gperf" {"error_category", "<system_error>", cxx11}, -#line 82 "../../src/gcc/cp/std-name-hint.gperf" +#line 82 "std-name-hint.gperf" {"chrono::round", "<chrono>", cxx17}, -#line 357 "../../src/gcc/cp/std-name-hint.gperf" +#line 357 "std-name-hint.gperf" {"unique_lock", "<mutex>", cxx11}, -#line 319 "../../src/gcc/cp/std-name-hint.gperf" +#line 319 "std-name-hint.gperf" {"make_shared", "<memory>", cxx11}, -#line 507 "../../src/gcc/cp/std-name-hint.gperf" +#line 507 "std-name-hint.gperf" {"this_thread", "<thread>", cxx11}, -#line 449 "../../src/gcc/cp/std-name-hint.gperf" +#line 449 "std-name-hint.gperf" {"invalid_argument", "<stdexcept>", cxx98}, -#line 354 "../../src/gcc/cp/std-name-hint.gperf" +#line 354 "std-name-hint.gperf" {"scoped_lock", "<mutex>", cxx17}, -#line 268 "../../src/gcc/cp/std-name-hint.gperf" +#line 268 "std-name-hint.gperf" {"wclog", "<iostream>", cxx98}, -#line 506 "../../src/gcc/cp/std-name-hint.gperf" +#line 506 "std-name-hint.gperf" {"jthread", "<thread>", cxx20}, -#line 97 "../../src/gcc/cp/std-name-hint.gperf" +#line 97 "std-name-hint.gperf" {"partial_ordering", "<compare>", cxx20}, -#line 68 "../../src/gcc/cp/std-name-hint.gperf" +#line 68 "std-name-hint.gperf" {"chrono::high_resolution_clock", "<chrono>", cxx11}, -#line 307 "../../src/gcc/cp/std-name-hint.gperf" +#line 307 "std-name-hint.gperf" {"assume_aligned", "<memory>", cxx20}, -#line 488 "../../src/gcc/cp/std-name-hint.gperf" +#line 488 "std-name-hint.gperf" {"wstring", "<string>", cxx98}, -#line 192 "../../src/gcc/cp/std-name-hint.gperf" +#line 192 "std-name-hint.gperf" {"wformat_string", "<format>", cxx20}, -#line 189 "../../src/gcc/cp/std-name-hint.gperf" +#line 189 "std-name-hint.gperf" {"wformat_args", "<format>", cxx20} }; diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 5863b68..e354da0 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -488,6 +488,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) case CP_BUILT_IN_SOURCE_LOCATION: case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: + case CP_BUILT_IN_EH_PTR_ADJUST_REF: return true; default: break; @@ -1185,7 +1186,12 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent) for (t = m; t; t = TYPE_NEXT_VARIANT (t)) if (TREE_TYPE (t) == elt_type && TYPE_NAME (t) == NULL_TREE - && TYPE_ATTRIBUTES (t) == NULL_TREE) + && TYPE_ATTRIBUTES (t) == NULL_TREE + && (!TYPE_USER_ALIGN (t) + || (TYPE_USER_ALIGN (elt_type) + && TYPE_ALIGN (t) == TYPE_ALIGN (elt_type))) + && !TREE_DEPRECATED (t) + && !TREE_UNAVAILABLE (t)) break; if (!t) { @@ -3695,6 +3701,58 @@ build_min_non_dep_op_overload (enum tree_code op, int nargs, expected_nargs; tree fn, call, obj = NULL_TREE; + releasing_vec args; + va_start (p, overload); + + bool negated = false, rewritten = false, reversed = false; + if (cxx_dialect >= cxx20 && TREE_CODE (overload) == TREE_LIST) + { + /* Handle rebuilding a C++20 rewritten comparison operator expression, + e.g. !(x == y), y <=> x, (x <=> y) @ 0 etc, that resolved to a call + to a user-defined operator<=>/==. */ + gcc_checking_assert (TREE_CODE_CLASS (op) == tcc_comparison + || op == SPACESHIP_EXPR); + int flags = TREE_INT_CST_LOW (TREE_PURPOSE (overload)); + if (TREE_CODE (non_dep) == TRUTH_NOT_EXPR) + { + negated = true; + non_dep = TREE_OPERAND (non_dep, 0); + } + if (flags & LOOKUP_REWRITTEN) + rewritten = true; + if (flags & LOOKUP_REVERSED) + reversed = true; + if (rewritten + && DECL_OVERLOADED_OPERATOR_IS (TREE_VALUE (overload), + SPACESHIP_EXPR)) + { + /* Handle (x <=> y) @ 0 and 0 @ (y <=> x) by recursing to first + rebuild the <=>. Note that both OVERLOAD and the provided arguments + in this case already correspond to the selected operator<=>. */ + + tree spaceship_non_dep = CALL_EXPR_ARG (non_dep, reversed ? 1 : 0); + gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR); + tree spaceship_op0 = va_arg (p, tree); + tree spaceship_op1 = va_arg (p, tree); + if (reversed) + std::swap (spaceship_op0, spaceship_op1); + + /* Push the correct arguments for the operator OP expression, and + set OVERLOAD appropriately. */ + tree op0 = build_min_non_dep_op_overload (SPACESHIP_EXPR, + spaceship_non_dep, + TREE_VALUE (overload), + spaceship_op0, + spaceship_op1); + tree op1 = CALL_EXPR_ARG (non_dep, reversed ? 0 : 1); + gcc_checking_assert (integer_zerop (op1)); + vec_safe_push (args, op0); + vec_safe_push (args, op1); + overload = CALL_EXPR_FN (non_dep); + } + else + overload = TREE_VALUE (overload); + } non_dep = extract_call_expr (non_dep); nargs = call_expr_nargs (non_dep); @@ -3715,32 +3773,40 @@ build_min_non_dep_op_overload (enum tree_code op, expected_nargs += 1; gcc_assert (nargs == expected_nargs); - releasing_vec args; - va_start (p, overload); - if (!DECL_OBJECT_MEMBER_FUNCTION_P (overload)) { fn = overload; - if (op == ARRAY_REF) - obj = va_arg (p, tree); - for (int i = 0; i < nargs; i++) + if (vec_safe_length (args) != 0) + /* The correct arguments were already pushed above. */ + gcc_checking_assert (rewritten); + else { - tree arg = va_arg (p, tree); - vec_safe_push (args, arg); + if (op == ARRAY_REF) + obj = va_arg (p, tree); + for (int i = 0; i < nargs; i++) + { + tree arg = va_arg (p, tree); + vec_safe_push (args, arg); + } } + if (reversed) + std::swap ((*args)[0], (*args)[1]); } else { + gcc_checking_assert (vec_safe_length (args) == 0); tree object = va_arg (p, tree); - tree binfo = TYPE_BINFO (TREE_TYPE (object)); - tree method = build_baselink (binfo, binfo, overload, NULL_TREE); - fn = build_min (COMPONENT_REF, TREE_TYPE (overload), - object, method, NULL_TREE); for (int i = 0; i < nargs; i++) { tree arg = va_arg (p, tree); vec_safe_push (args, arg); } + if (reversed) + std::swap (object, (*args)[0]); + tree binfo = TYPE_BINFO (TREE_TYPE (object)); + tree method = build_baselink (binfo, binfo, overload, NULL_TREE); + fn = build_min (COMPONENT_REF, TREE_TYPE (overload), + object, method, NULL_TREE); } va_end (p); @@ -3752,6 +3818,8 @@ build_min_non_dep_op_overload (enum tree_code op, CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep); CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep); + if (negated) + call = build_min (TRUTH_NOT_EXPR, boolean_type_node, call); if (obj) return keep_unused_object_arg (call, obj, overload); return call; @@ -4715,6 +4783,293 @@ trivial_type_p (const_tree t) return scalarish_type_p (t); } +/* Returns 1 iff type T is a default-movable type, as defined in + [class.prop]. */ + +static bool +default_movable_type_p (tree t) +{ + if (!CLASS_TYPE_P (t) || !COMPLETE_TYPE_P (t)) + return false; + if (CLASSTYPE_LAZY_DESTRUCTOR (t)) + lazily_declare_fn (sfk_destructor, t); + if (tree dtor = CLASSTYPE_DESTRUCTOR (t)) + if (user_provided_p (dtor) || DECL_DELETED_FN (dtor)) + return false; + + tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE; + tree copy_assign = NULL_TREE, move_assign = NULL_TREE; + if (CLASSTYPE_LAZY_MOVE_CTOR (t)) + move_ctor = lazily_declare_fn (sfk_move_constructor, t); + if (CLASSTYPE_LAZY_MOVE_ASSIGN (t)) + move_assign = lazily_declare_fn (sfk_move_assignment, t); + if (!move_ctor) + for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL) + { + if (copy_fn_p (*iter)) + copy_ctor = *iter; + else if (move_fn_p (*iter)) + { + move_ctor = *iter; + break; + } + } + if (!move_assign) + for (ovl_iterator iter (get_class_binding_direct (t, + assign_op_identifier)); + iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL) + { + if (copy_fn_p (*iter)) + copy_assign = *iter; + else if (move_fn_p (*iter)) + { + move_assign = *iter; + break; + } + } + if (!move_ctor) + { + if (CLASSTYPE_LAZY_COPY_CTOR (t)) + copy_ctor = lazily_declare_fn (sfk_copy_constructor, t); + if (!copy_ctor) + return false; + if (user_provided_p (copy_ctor) + || DECL_DELETED_FN (copy_ctor) + || DECL_CONTEXT (copy_ctor) != t + || DECL_INHERITED_CTOR (copy_ctor)) + return false; + } + else if (user_provided_p (move_ctor) + || DECL_DELETED_FN (move_ctor) + || DECL_CONTEXT (move_ctor) != t + || DECL_INHERITED_CTOR (move_ctor)) + return false; + if (!move_assign) + { + if (CLASSTYPE_LAZY_COPY_ASSIGN (t)) + copy_assign = lazily_declare_fn (sfk_copy_assignment, t); + if (!copy_assign) + return false; + if (user_provided_p (copy_assign) + || DECL_DELETED_FN (copy_assign) + || DECL_CONTEXT (copy_assign) != t) + return false; + } + else if (user_provided_p (move_assign) + || DECL_DELETED_FN (move_assign) + || DECL_CONTEXT (move_assign) != t) + return false; + return true; +} + +/* Returns 1 iff type T is a union with no user declared special member + functions. */ + +static bool +union_with_no_declared_special_member_fns (tree t) +{ + if (TREE_CODE (t) != UNION_TYPE) + return false; + + for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL + && !DECL_ARTIFICIAL (*iter) + && (default_ctor_p (*iter) || copy_fn_p (*iter) || move_fn_p (*iter))) + return false; + + for (ovl_iterator iter (get_class_binding_direct (t, assign_op_identifier)); + iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL + && !DECL_ARTIFICIAL (*iter) + && (copy_fn_p (*iter) || move_fn_p (*iter))) + return false; + + if (tree dtor = CLASSTYPE_DESTRUCTOR (t)) + if (!DECL_ARTIFICIAL (dtor)) + return false; + + return true; +} + +/* Returns 1 iff type T is a trivially relocatable type, as defined in + [basic.types.general] and [class.prop]. */ + +bool +trivially_relocatable_type_p (tree t) +{ + t = strip_array_types (t); + + if (!CLASS_TYPE_P (t)) + return scalarish_type_p (t); + + t = TYPE_MAIN_VARIANT (t); + if (CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t)) + return CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t); + if (!COMPLETE_TYPE_P (t)) + return false; + + if (!CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) + && !union_with_no_declared_special_member_fns (t) + && !default_movable_type_p (t)) + { + nontriv: + CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) = 0; + CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1; + return false; + } + + if (CLASSTYPE_VBASECLASSES (t)) + goto nontriv; + + if (CLASSTYPE_LAZY_DESTRUCTOR (t)) + lazily_declare_fn (sfk_destructor, t); + if (tree dtor = CLASSTYPE_DESTRUCTOR (t)) + if (DECL_DELETED_FN (dtor)) + goto nontriv; + + tree binfo, base_binfo; + unsigned int i; + for (binfo = TYPE_BINFO (t), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + tree basetype = TREE_TYPE (base_binfo); + if (!trivially_relocatable_type_p (basetype)) + goto nontriv; + } + + for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && !DECL_ARTIFICIAL (field) + && !DECL_UNNAMED_BIT_FIELD (field)) + { + tree type = TREE_TYPE (field); + if (type == error_mark_node) + goto nontriv; + if (!TYPE_REF_P (type) && !trivially_relocatable_type_p (type)) + goto nontriv; + } + + CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) = 1; + CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1; + return true; +} + +/* Returns 1 iff type T is a replaceable type, as defined in [basic.types] + and [class]. */ + +bool +replaceable_type_p (tree t) +{ + t = strip_array_types (t); + + if (cv_qualified_p (t)) + return false; + + if (!CLASS_TYPE_P (t)) + return scalarish_type_p (t); + + t = TYPE_MAIN_VARIANT (t); + if (CLASSTYPE_REPLACEABLE_COMPUTED (t)) + return CLASSTYPE_REPLACEABLE_BIT (t); + if (!COMPLETE_TYPE_P (t)) + return false; + + if (!CLASSTYPE_REPLACEABLE_BIT (t) + && !union_with_no_declared_special_member_fns (t) + && !default_movable_type_p (t)) + { + nonrepl: + CLASSTYPE_REPLACEABLE_BIT (t) = 0; + CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1; + return false; + } + + if (CLASSTYPE_LAZY_DESTRUCTOR (t)) + lazily_declare_fn (sfk_destructor, t); + if (tree dtor = CLASSTYPE_DESTRUCTOR (t)) + if (DECL_DELETED_FN (dtor)) + goto nonrepl; + + tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE; + tree copy_assign = NULL_TREE, move_assign = NULL_TREE; + if (CLASSTYPE_LAZY_MOVE_CTOR (t)) + move_ctor = lazily_declare_fn (sfk_move_constructor, t); + if (CLASSTYPE_LAZY_MOVE_ASSIGN (t)) + move_assign = lazily_declare_fn (sfk_move_assignment, t); + if (!move_ctor) + for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL) + { + if (copy_fn_p (*iter)) + copy_ctor = *iter; + else if (move_fn_p (*iter)) + { + move_ctor = *iter; + break; + } + } + if (!move_assign) + for (ovl_iterator iter (get_class_binding_direct (t, + assign_op_identifier)); + iter; ++iter) + if (TREE_CODE (*iter) == FUNCTION_DECL) + { + if (copy_fn_p (*iter)) + copy_assign = *iter; + else if (move_fn_p (*iter)) + { + move_assign = *iter; + break; + } + } + if (!move_ctor) + { + if (CLASSTYPE_LAZY_COPY_CTOR (t)) + copy_ctor = lazily_declare_fn (sfk_copy_constructor, t); + if (!copy_ctor || DECL_DELETED_FN (copy_ctor)) + goto nonrepl; + } + else if (DECL_DELETED_FN (move_ctor)) + goto nonrepl; + if (!move_assign) + { + if (CLASSTYPE_LAZY_COPY_ASSIGN (t)) + copy_assign = lazily_declare_fn (sfk_copy_assignment, t); + if (!copy_assign || DECL_DELETED_FN (copy_assign)) + goto nonrepl; + } + else if (DECL_DELETED_FN (move_assign)) + goto nonrepl; + + tree binfo, base_binfo; + unsigned int i; + for (binfo = TYPE_BINFO (t), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + tree basetype = TREE_TYPE (base_binfo); + if (!replaceable_type_p (basetype)) + goto nonrepl; + } + + for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && !DECL_ARTIFICIAL (field) + && !DECL_UNNAMED_BIT_FIELD (field)) + { + tree type = TREE_TYPE (field); + if (type == error_mark_node) + goto nonrepl; + if (!replaceable_type_p (type)) + goto nonrepl; + } + + CLASSTYPE_REPLACEABLE_BIT (t) = 1; + CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1; + return true; +} + /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ bool @@ -6044,8 +6399,8 @@ decl_linkage (tree decl) if (NAMESPACE_SCOPE_P (decl) && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl)))) { - if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl))) - /* This entity has a typedef name for linkage purposes. */; + if (TREE_CODE (decl) == TYPE_DECL && !TYPE_UNNAMED_P (TREE_TYPE (decl))) + /* This entity has a name for linkage purposes. */; else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl)) /* Namespace-scope structured bindings can have linkage. */; else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 88f8f34..ccfe50d 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -155,8 +155,8 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain) else if (!COMPLETE_TYPE_P (type)) { if (complain & tf_error) - cxx_incomplete_type_diagnostic (value, type, DK_ERROR); - note_failed_type_completion_for_satisfaction (type); + cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error); + note_failed_type_completion (type, complain); return NULL_TREE; } else @@ -618,7 +618,7 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2) static void composite_pointer_error (const op_location_t &location, - diagnostic_t kind, tree t1, tree t2, + enum diagnostics::kind kind, tree t1, tree t2, composite_pointer_operation operation) { switch (operation) @@ -690,7 +690,7 @@ composite_pointer_type_r (const op_location_t &location, else { if (complain & tf_error) - composite_pointer_error (location, DK_PERMERROR, + composite_pointer_error (location, diagnostics::kind::permerror, t1, t2, operation); else return error_mark_node; @@ -716,7 +716,7 @@ composite_pointer_type_r (const op_location_t &location, TYPE_PTRMEM_CLASS_TYPE (t2))) { if (complain & tf_error) - composite_pointer_error (location, DK_PERMERROR, + composite_pointer_error (location, diagnostics::kind::permerror, t1, t2, operation); else return error_mark_node; @@ -851,7 +851,8 @@ composite_pointer_type (const op_location_t &location, else { if (complain & tf_error) - composite_pointer_error (location, DK_ERROR, t1, t2, operation); + composite_pointer_error (location, diagnostics::kind::error, + t1, t2, operation); return error_mark_node; } } @@ -1372,17 +1373,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 +2085,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 +2114,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 @@ -3970,7 +3973,6 @@ tree cp_build_array_ref (location_t loc, tree array, tree idx, tsubst_flags_t complain) { - tree first = NULL_TREE; tree ret; if (idx == 0) @@ -3984,6 +3986,21 @@ cp_build_array_ref (location_t loc, tree array, tree idx, || TREE_TYPE (idx) == error_mark_node) return error_mark_node; + /* 0[array] */ + if (TREE_CODE (TREE_TYPE (idx)) == ARRAY_TYPE) + { + std::swap (array, idx); + + tree first = NULL_TREE; + if (flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (array)) + idx = first = save_expr (idx); + ret = cp_build_array_ref (loc, array, idx, complain); + + if (first) + ret = build2 (COMPOUND_EXPR, TREE_TYPE (ret), first, ret); + return ret; + } + /* If ARRAY is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */ switch (TREE_CODE (array)) @@ -3999,13 +4016,61 @@ cp_build_array_ref (location_t loc, tree array, tree idx, } case COND_EXPR: - ret = build_conditional_expr - (loc, TREE_OPERAND (array, 0), - cp_build_array_ref (loc, TREE_OPERAND (array, 1), idx, - complain), - cp_build_array_ref (loc, TREE_OPERAND (array, 2), idx, - complain), - complain); + tree op0, op1, op2; + op0 = TREE_OPERAND (array, 0); + op1 = TREE_OPERAND (array, 1); + op2 = TREE_OPERAND (array, 2); + if (TREE_SIDE_EFFECTS (idx) || !tree_invariant_p (idx)) + { + /* If idx could possibly have some SAVE_EXPRs, turning + (op0 ? op1 : op2)[idx] into + op0 ? op1[idx] : op2[idx] can lead into temporaries + initialized in one conditional path and uninitialized + uses of them in the other path. + And if idx is a really large expression, evaluating it + twice is also not optimal. + On the other side, op0 must be sequenced before evaluation + of op1 and op2 and for C++17 op0, op1 and op2 must be + sequenced before idx. + If idx is INTEGER_CST, we can just do the optimization + without any SAVE_EXPRs, if op1 and op2 are both ARRAY_TYPE + VAR_DECLs or COMPONENT_REFs thereof (so their address + is constant or relative to frame), optimize into + (SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0>) + ? op1[SAVE_EXPR <idx>] : op2[SAVE_EXPR <idx>] + Otherwise avoid this optimization. */ + if (flag_strong_eval_order == 2) + { + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) + { + if (!address_invariant_p (op1) || !address_invariant_p (op2)) + { + /* Force default conversion on array if + we can't optimize this and array is ARRAY_TYPE + COND_EXPR, we can't leave COND_EXPRs with + ARRAY_TYPE in the IL. */ + array = cp_default_conversion (array, complain); + if (error_operand_p (array)) + return error_mark_node; + break; + } + } + else if (!POINTER_TYPE_P (TREE_TYPE (array)) + || !tree_invariant_p (op1) + || !tree_invariant_p (op2)) + break; + } + if (TREE_SIDE_EFFECTS (idx)) + { + idx = save_expr (idx); + op0 = save_expr (op0); + tree tem = build_compound_expr (loc, op0, idx); + op0 = build_compound_expr (loc, tem, op0); + } + } + op1 = cp_build_array_ref (loc, op1, idx, complain); + op2 = cp_build_array_ref (loc, op2, idx, complain); + ret = build_conditional_expr (loc, op0, op1, op2, complain); protected_set_expr_location (ret, loc); return ret; @@ -4015,14 +4080,6 @@ cp_build_array_ref (location_t loc, tree array, tree idx, bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, idx); - /* 0[array] */ - if (TREE_CODE (TREE_TYPE (idx)) == ARRAY_TYPE) - { - std::swap (array, idx); - if (flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (array)) - idx = first = save_expr (idx); - } - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) { tree rval, type; @@ -4098,17 +4155,16 @@ cp_build_array_ref (location_t loc, tree array, tree idx, protected_set_expr_location (ret, loc); if (non_lvalue) ret = non_lvalue_loc (loc, ret); - if (first) - ret = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (ret), first, ret); return ret; } { tree ar = cp_default_conversion (array, complain); tree ind = cp_default_conversion (idx, complain); + tree first = NULL_TREE; - if (!processing_template_decl - && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind)) + if (!processing_template_decl && flag_strong_eval_order == 2 + && TREE_SIDE_EFFECTS (ind)) ar = first = save_expr (ar); /* Put the integer in IND to simplify error checking. */ @@ -4236,7 +4292,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, idx = build1 (NOP_EXPR, vtable_index_type, e3); switch (TARGET_PTRMEMFUNC_VBIT_LOCATION) { - int flag_sanitize_save; + sanitize_code_type flag_sanitize_save; case ptrmemfunc_vbit_in_pfn: e1 = cp_build_binary_op (input_location, BIT_AND_EXPR, idx, integer_one_node, @@ -4480,7 +4536,11 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params, { if (complain & tf_error) { - if (!flag_diagnostics_show_caret) + if (is_stub_object (original)) + error_at (input_location, + "%qT cannot be used as a function", + TREE_TYPE (original)); + else if (!flag_diagnostics_show_caret) error_at (input_location, "%qE cannot be used as a function", original); else if (DECL_P (original)) @@ -4622,12 +4682,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl, if (type == void_type_node) { if (complain & tf_error) - { - error_args_num (input_location, fndecl, /*too_many_p=*/true); - return i; - } - else - return -1; + error_args_num (input_location, fndecl, /*too_many_p=*/true); + return -1; } /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. @@ -7630,7 +7686,18 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, if (val != 0) goto return_build_unary_op; - arg = mark_lvalue_use (arg); + tree stripped_arg; + stripped_arg = tree_strip_any_location_wrapper (arg); + if ((VAR_P (stripped_arg) || TREE_CODE (stripped_arg) == PARM_DECL) + && !DECL_READ_P (stripped_arg) + && (VAR_P (stripped_arg) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 1) + { + arg = mark_lvalue_use (arg); + DECL_READ_P (stripped_arg) = 0; + } + else + arg = mark_lvalue_use (arg); /* Increment or decrement the real part of the value, and don't change the imaginary part. */ @@ -9746,7 +9813,22 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { auto_diagnostic_group d; rhs = stabilize_expr (rhs, &init); + bool clear_decl_read = false; + tree stripped_lhs = tree_strip_any_location_wrapper (lhs); + if ((VAR_P (stripped_lhs) || TREE_CODE (stripped_lhs) == PARM_DECL) + && !DECL_READ_P (stripped_lhs) + && (VAR_P (stripped_lhs) ? warn_unused_but_set_variable + : warn_unused_but_set_parameter) > 2 + && !CLASS_TYPE_P (TREE_TYPE (lhs)) + && !CLASS_TYPE_P (TREE_TYPE (rhs))) + { + mark_exp_read (rhs); + if (!DECL_READ_P (stripped_lhs)) + clear_decl_read = true; + } newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain); + if (clear_decl_read) + DECL_READ_P (stripped_lhs) = 0; if (newrhs == error_mark_node) { if (complain & tf_error) @@ -10729,7 +10811,9 @@ maybe_warn_about_returning_address_of_local (tree retval, location_t loc) { if (TYPE_REF_P (valtype)) /* P2748 made this an error in C++26. */ - emit_diagnostic (cxx_dialect >= cxx26 ? DK_PERMERROR : DK_WARNING, + emit_diagnostic ((cxx_dialect >= cxx26 + ? diagnostics::kind::permerror + : diagnostics::kind::warning), loc, OPT_Wreturn_local_addr, "returning reference to temporary"); else if (TYPE_PTR_P (valtype)) @@ -11468,6 +11552,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. */ diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 45edd18..d77de92 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -119,6 +119,11 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring) G_("increment of read-only reference %qD"), G_("decrement of read-only reference %qD"), TREE_OPERAND (arg, 0)); + else if (is_stub_object (arg)) + { + gcc_assert (errstring == lv_assign); + error_at (loc, "assignment to read-only type %qT", TREE_TYPE (arg)); + } else readonly_error (loc, arg, errstring); } @@ -276,25 +281,107 @@ cxx_incomplete_type_inform (const_tree type) location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)); tree ptype = strip_top_quals (CONST_CAST_TREE (type)); + /* When defining a template, current_class_type will be the pattern on + the template definition, while non-self-reference usages of this + template will be an instantiation; we should pull out the pattern to + compare against. And for partial specs we should use the loc of the + partial spec rather than the primary template. */ + tree ttype = NULL_TREE; + tree tinfo = TYPE_TEMPLATE_INFO (ptype); + if (tinfo) + { + tree tmpl = TI_TEMPLATE (tinfo); + if (PRIMARY_TEMPLATE_P (tmpl) && TI_PARTIAL_INFO (tinfo)) + { + tree partial = TI_TEMPLATE (TI_PARTIAL_INFO (tinfo)); + loc = DECL_SOURCE_LOCATION (partial); + ttype = TREE_TYPE (partial); + } + else + ttype = TREE_TYPE (tmpl); + } + if (current_class_type && TYPE_BEING_DEFINED (current_class_type) - && same_type_p (ptype, current_class_type)) + && (same_type_p (ptype, current_class_type) + || (ttype && same_type_p (ttype, current_class_type)))) inform (loc, "definition of %q#T is not complete until " "the closing brace", ptype); - else if (!TYPE_TEMPLATE_INFO (ptype)) - inform (loc, "forward declaration of %q#T", ptype); else - inform (loc, "declaration of %q#T", ptype); + { + if (!tinfo) + inform (loc, "forward declaration of %q#T", ptype); + else + inform (loc, "declaration of %q#T", ptype); + + /* If there's a similar-looking complete type attached + to a different module, point at that as a suggestion. */ + if (modules_p () && TYPE_NAMESPACE_SCOPE_P (ptype)) + { + tree result = lookup_qualified_name (CP_TYPE_CONTEXT (ptype), + TYPE_IDENTIFIER (ptype), + LOOK_want::TYPE); + if (TREE_CODE (result) == TREE_LIST) + for (; result; result = TREE_CHAIN (result)) + { + tree cand = TREE_VALUE (result); + + /* Typedefs are not likely intended to correspond. */ + if (is_typedef_decl (STRIP_TEMPLATE (cand)) + || DECL_ALIAS_TEMPLATE_P (cand)) + continue; + + /* Only look at templates if type was a template. */ + if ((tinfo != nullptr) != (TREE_CODE (cand) == TEMPLATE_DECL)) + continue; + + /* If we're looking for a template specialisation, + only consider matching specialisations. */ + if (tinfo) + { + tree t = lookup_template_class (cand, TI_ARGS (tinfo), + NULL_TREE, NULL_TREE, + tf_none); + if (t == error_mark_node + || !CLASS_TYPE_P (t) + || TYPE_BEING_DEFINED (t)) + continue; + + if (CLASSTYPE_TEMPLATE_INSTANTIATION (t)) + { + /* An uninstantiated template: check if there is a + pattern that could be used. We don't want to + call instantiate_class_template as that could + cause further errors; this is just a hint. */ + tree part = most_specialized_partial_spec (t, tf_none); + cand = (part ? TI_TEMPLATE (part) + : CLASSTYPE_TI_TEMPLATE (t)); + } + else + cand = TYPE_NAME (t); + } + + if (!COMPLETE_TYPE_P (TREE_TYPE (cand))) + continue; + + inform (DECL_SOURCE_LOCATION (cand), + "%q#T has a definition but does not correspond with " + "%q#T because it is attached to a different module", + TREE_TYPE (cand), ptype); + } + } + } } /* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) and TYPE is the type that was invalid. DIAG_KIND indicates the - type of diagnostic (see diagnostic.def). */ + type of diagnostic (see diagnostics/kinds.def). */ bool cxx_incomplete_type_diagnostic (location_t loc, const_tree value, - const_tree type, diagnostic_t diag_kind) + const_tree type, + enum diagnostics::kind diag_kind) { bool is_decl = false, complained = false; @@ -440,7 +527,7 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value, void cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type) { - cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR); + cxx_incomplete_type_diagnostic (loc, value, type, diagnostics::kind::error); } @@ -2627,7 +2714,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) bool ok; tree core = spec; bool is_ptr; - diagnostic_t diag_type = DK_UNSPECIFIED; /* none */ + enum diagnostics::kind diag_type = diagnostics::kind::unspecified; /* none */ if (spec == error_mark_node) return list; @@ -2659,7 +2746,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) and calls. So just give a pedwarn at this point; we will give an error later if we hit one of those two cases. */ if (!COMPLETE_TYPE_P (complete_type (core))) - diag_type = DK_PEDWARN; /* pedwarn */ + diag_type = diagnostics::kind::pedwarn; /* pedwarn */ } if (ok) @@ -2673,9 +2760,9 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain) list = tree_cons (NULL_TREE, spec, list); } else - diag_type = DK_ERROR; /* error */ + diag_type = diagnostics::kind::error; /* error */ - if (diag_type != DK_UNSPECIFIED + if (diag_type != diagnostics::kind::unspecified && (complain & tf_warning_or_error)) cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type); |