diff options
Diffstat (limited to 'gcc/cp')
35 files changed, 3393 insertions, 595 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 08ec840..e32ee1c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,487 @@ +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. diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 9283d97..02cef63 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -7904,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 @@ -15054,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 f5d20e5..cf58f65 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -1356,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 diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index f92beb1..c3d0524 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "intl.h" #include "toplev.h" +#include "contracts.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -2694,6 +2695,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, 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) @@ -2711,8 +2714,6 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) break; - if (*jump_target) - break; /* Just discard ellipsis args after checking their constantitude. */ if (!parms) continue; @@ -3240,7 +3241,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. @@ -6598,6 +6603,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, return cxx_eval_bare_aggregate (ctx, init, lval, 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 here, as for a constructor to be constexpr, all members must be @@ -7172,10 +7180,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; } @@ -7445,12 +7466,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, 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. - ??? We should probably set CONSTRUCTOR_NO_CLEARING. */ - return void_node; - /* First we figure out where we're storing to. */ tree target = TREE_OPERAND (t, 0); @@ -7637,11 +7652,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); @@ -7778,6 +7799,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))) @@ -7841,11 +7864,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; @@ -7952,8 +7981,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 @@ -7966,6 +7997,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) { @@ -7990,6 +8037,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))))) @@ -7997,7 +8047,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; } @@ -10329,11 +10379,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 @@ -11298,6 +11351,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, @@ -11559,12 +11619,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)) @@ -12121,6 +12183,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: @@ -12415,6 +12479,7 @@ 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); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index d4a83e4..4b20b79 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3176,8 +3176,7 @@ diagnose_trait_expr (location_t loc, tree expr, tree args) inform (loc, "%qT is not invocable, because", t1); else inform (loc, "%qT is not invocable by %qT, because", t1, t2); - tree call = build_invoke (t1, t2, tf_error); - gcc_assert (call == error_mark_node); + build_invoke (t1, t2, tf_error); } break; case CPTK_IS_LAYOUT_COMPATIBLE: @@ -3305,6 +3304,9 @@ diagnose_trait_expr (location_t loc, tree expr, tree args) 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 " "object of type %qT (direct-initialization)", t1, t2); diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index d0cfd2e..042524d 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -159,7 +159,7 @@ bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = { { 0, 1, 0, 0, 1, }, }; -void +static void validate_contract_role (contract_role *role) { gcc_assert (role); @@ -171,7 +171,7 @@ validate_contract_role (contract_role *role) "the %<default%> semantic"); } -contract_semantic +static contract_semantic lookup_concrete_semantic (const char *name) { if (strcmp (name, "ignore") == 0) @@ -210,7 +210,9 @@ role_name_equal (contract_role *role, const char *name) return role_name_equal (role->name, name); } -contract_role * +static void setup_default_contract_role (bool update = true); + +static contract_role * get_contract_role (const char *name) { for (int i = 0; i < max_custom_roles; ++i) @@ -227,12 +229,12 @@ get_contract_role (const char *name) return NULL; } -contract_role * +static contract_role * add_contract_role (const char *name, contract_semantic des, contract_semantic aus, contract_semantic axs, - bool update) + bool update = true) { for (int i = 0; i < max_custom_roles; ++i) { @@ -271,7 +273,7 @@ get_concrete_axiom_semantic () return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE; } -void +static void setup_default_contract_role (bool update) { contract_semantic check = get_concrete_check (); @@ -491,6 +493,14 @@ handle_OPT_fcontract_semantic_ (const char *arg) validate_contract_role (role); } +/* Returns the default role. */ + +static contract_role * +get_default_contract_role () +{ + return get_contract_role ("default"); +} + /* Convert a contract CONFIG into a contract_mode. */ static contract_mode diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h index 7d955f7..ead07d1 100644 --- a/gcc/cp/contracts.h +++ b/gcc/cp/contracts.h @@ -131,38 +131,20 @@ struct contract_mode } u; }; -extern contract_role *get_contract_role (const char *); -extern contract_role *add_contract_role (const char *, - contract_semantic, - contract_semantic, - contract_semantic, - bool = true); -extern void validate_contract_role (contract_role *); -extern void setup_default_contract_role (bool = true); -extern contract_semantic lookup_concrete_semantic (const char *); - /* Map a source level semantic or level name to its value, or invalid. */ extern contract_semantic map_contract_semantic (const char *); extern contract_level map_contract_level (const char *); /* Check if an attribute is a cxx contract attribute. */ -extern bool cxx_contract_attribute_p (const_tree); -extern bool cp_contract_assertion_p (const_tree); - -/* Returns the default role. */ - -inline contract_role * -get_default_contract_role () -{ - return get_contract_role ("default"); -} +extern bool cxx_contract_attribute_p (const_tree); +extern bool cp_contract_assertion_p (const_tree); /* Handle various command line arguments related to semantic mapping. */ -extern void handle_OPT_fcontract_build_level_ (const char *); +extern void handle_OPT_fcontract_build_level_ (const char *); extern void handle_OPT_fcontract_assumption_mode_ (const char *); extern void handle_OPT_fcontract_continuation_mode_ (const char *); -extern void handle_OPT_fcontract_role_ (const char *); -extern void handle_OPT_fcontract_semantic_ (const char *); +extern void handle_OPT_fcontract_role_ (const char *); +extern void handle_OPT_fcontract_semantic_ (const char *); enum contract_matching_context { @@ -277,29 +259,79 @@ enum contract_matching_context #define DECL_IS_POST_FN_P(NODE) \ (DECL_ABSTRACT_ORIGIN (NODE) && DECL_POST_FN (DECL_ABSTRACT_ORIGIN (NODE)) == NODE) +/* contracts.cc */ +extern void emit_assertion (tree); + extern void remove_contract_attributes (tree); +extern bool all_attributes_are_contracts_p (tree); +extern tree finish_contract_attribute (tree, tree); extern void copy_contract_attributes (tree, tree); +extern bool diagnose_misapplied_contracts (tree); extern void remap_contracts (tree, tree, tree, bool); +extern tree splice_out_contracts (tree); +extern void inherit_base_contracts (tree, tree); + +extern tree make_postcondition_variable (cp_expr); +extern tree make_postcondition_variable (cp_expr, tree); extern void maybe_update_postconditions (tree); extern void rebuild_postconditions (tree); extern bool check_postcondition_result (tree, tree, location_t); -extern tree get_precondition_function (tree); -extern tree get_postcondition_function (tree); + +extern tree grok_contract (tree, tree, tree, cp_expr, + location_t); +extern tree finish_contract_condition (cp_expr); +extern void update_late_contract (tree, tree, tree); +extern tree invalidate_contract (tree); extern void duplicate_contracts (tree, tree); + extern void match_deferred_contracts (tree); extern void defer_guarded_contract_match (tree, tree, tree); -extern bool diagnose_misapplied_contracts (tree); -extern tree finish_contract_attribute (tree, tree); -extern tree invalidate_contract (tree); -extern void update_late_contract (tree, tree, tree); -extern tree splice_out_contracts (tree); -extern bool all_attributes_are_contracts_p (tree); -extern void inherit_base_contracts (tree, tree); + +extern tree get_precondition_function (tree); +extern tree get_postcondition_function (tree); extern void start_function_contracts (tree); extern void maybe_apply_function_contracts (tree); extern void finish_function_contracts (tree); extern void set_contract_functions (tree, tree, tree); + extern tree build_contract_check (tree); -extern void emit_assertion (tree); + +/* Return the first contract in ATTRS, or NULL_TREE if there are none. */ + +inline tree +find_contract (tree attrs) +{ + while (attrs && !cxx_contract_attribute_p (attrs)) + attrs = TREE_CHAIN (attrs); + return attrs; +} + +inline void +set_decl_contracts (tree decl, tree contract_attrs) +{ + remove_contract_attributes (decl); + DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs); +} + +/* Returns the computed semantic of the node. */ + +inline contract_semantic +get_contract_semantic (const_tree t) +{ + return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) + | (TREE_LANG_FLAG_2 (t) << 1) + | (TREE_LANG_FLAG_0 ((t)) << 2)); +} + +/* Sets the computed semantic of the node. */ + +inline void +set_contract_semantic (tree t, contract_semantic semantic) +{ + TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01; + TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1; + TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2; +} + #endif /* ! GCC_CP_CONTRACT_H */ diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 690e510..af1c4bc 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc-rich-location.h" #include "hash-map.h" #include "coroutines.h" +#include "contracts.h" /* ================= Debug. ================= */ diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 4ff8f36a..39da4ff 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "omp-general.h" #include "opts.h" #include "gcc-urlifier.h" +#include "contracts.h" /* Keep track of forward references to immediate-escalating functions in case they become consteval. This vector contains ADDR_EXPRs and diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 7665b94..ee1c0ba 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -659,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-trait.def b/gcc/cp/cp-trait.def index 9fedfd7..5e4493a 100644 --- a/gcc/cp/cp-trait.def +++ b/gcc/cp/cp-trait.def @@ -117,6 +117,7 @@ DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1) DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1) DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) +DEFTRAIT_EXPR (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 0ac3ecb..8520ca0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -25,7 +25,6 @@ along with GCC; see the file COPYING3. If not see #include "hard-reg-set.h" #include "function.h" #include "tristate.h" -#include "contracts.h" /* In order for the format checking to accept the C++ front end diagnostic framework extensions, you must include this file before @@ -453,6 +452,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; 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. @@ -474,6 +475,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; 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) @@ -1433,6 +1435,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; @@ -1547,6 +1553,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)) @@ -1963,6 +1980,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; @@ -2036,6 +2055,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 @@ -2320,7 +2340,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))) @@ -5681,6 +5702,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) @@ -6792,9 +6826,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 @@ -7268,6 +7304,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); @@ -7288,6 +7325,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); @@ -7750,8 +7788,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); @@ -7764,6 +7806,8 @@ 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); @@ -7968,6 +8012,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. */ @@ -8068,6 +8113,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); @@ -8094,7 +8140,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); @@ -8243,10 +8289,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); @@ -8268,7 +8315,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); @@ -8291,6 +8338,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); @@ -9061,50 +9109,6 @@ extern tree coro_get_ramp_function (tree); extern tree co_await_get_resume_call (tree await_expr); - -/* contracts.cc */ -extern tree make_postcondition_variable (cp_expr); -extern tree make_postcondition_variable (cp_expr, tree); -extern tree grok_contract (tree, tree, tree, cp_expr, location_t); -extern tree finish_contract_condition (cp_expr); - -/* Return the first contract in ATTRS, or NULL_TREE if there are none. */ - -inline tree -find_contract (tree attrs) -{ - while (attrs && !cxx_contract_attribute_p (attrs)) - attrs = TREE_CHAIN (attrs); - return attrs; -} - -inline void -set_decl_contracts (tree decl, tree contract_attrs) -{ - remove_contract_attributes (decl); - DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs); -} - -/* Returns the computed semantic of the node. */ - -inline contract_semantic -get_contract_semantic (const_tree t) -{ - return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) - | (TREE_LANG_FLAG_2 (t) << 1) - | (TREE_LANG_FLAG_0 ((t)) << 2)); -} - -/* Sets the computed semantic of the node. */ - -inline void -set_contract_semantic (tree t, contract_semantic semantic) -{ - TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01; - TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1; - TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2; -} - /* Inline bodies. */ inline tree diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index 5f24015..4916bf6 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -2137,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: diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index cb3ebff..f088d09 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "opts.h" #include "langhooks-def.h" /* For lhd_simulate_record_decl */ #include "coroutines.h" +#include "contracts.h" #include "gcc-urlifier.h" #include "diagnostic-highlight-colors.h" #include "pretty-print-markup.h" @@ -572,9 +573,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: @@ -4336,7 +4337,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)); } @@ -8595,6 +8608,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; @@ -9633,13 +9653,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; } @@ -9653,6 +9677,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 " @@ -9665,6 +9691,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); @@ -9686,28 +9714,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 @@ -9738,7 +9770,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 @@ -9748,7 +9780,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); @@ -9764,7 +9796,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); @@ -9870,6 +9902,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 @@ -9926,10 +10086,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); @@ -9951,6 +10114,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; @@ -9969,7 +10140,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; @@ -9990,12 +10161,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; } @@ -10004,17 +10200,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; } @@ -10026,19 +10246,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; } @@ -10062,11 +10310,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 @@ -10096,16 +10344,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) @@ -10154,11 +10456,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; @@ -10170,7 +10479,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) @@ -10179,6 +10488,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 @@ -10191,6 +10501,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) @@ -10199,7 +10535,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) { @@ -12670,6 +13025,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. */ @@ -12677,7 +13114,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. */ @@ -12695,12 +13133,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) @@ -14950,7 +15392,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) @@ -17793,6 +18238,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. */ @@ -18023,6 +18480,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 ()); @@ -18440,6 +18902,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); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 2bbc618..6499be1 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "omp-general.h" #include "tree-inline.h" #include "escaped_string.h" +#include "contracts.h" /* Id for dumping the raw trees. */ int raw_dump_id; @@ -6229,6 +6230,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 @@ -6240,6 +6242,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; } diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index c427163..8ef9f9e 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -250,7 +250,7 @@ erroneous_templates_t *erroneous_templates; issue an error if we later need to instantiate the template. */ static void -cp_adjust_diagnostic_info (diagnostics::context *context, +cp_adjust_diagnostic_info (const diagnostics::context &context, diagnostics::diagnostic_info *diagnostic) { if (diagnostic->m_kind == diagnostics::kind::error) @@ -258,7 +258,7 @@ cp_adjust_diagnostic_info (diagnostics::context *context, { diagnostic->m_option_id = OPT_Wtemplate_body; - if (context->m_permissive) + if (context.m_permissive) diagnostic->m_kind = diagnostics::kind::warning; bool existed; @@ -3953,14 +3953,20 @@ print_instantiation_full_context (diagnostics::text_sink &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 () + 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; @@ -4069,7 +4075,14 @@ print_instantiation_partial_context_line (diagnostics::text_sink &text_output, 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 ? G_("recursively required by substitution of %qS\n") diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc index 2c1ef4c..204769f 100644 --- a/gcc/cp/except.cc +++ b/gcc/cp/except.cc @@ -1218,13 +1218,15 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain) return true; } -/* Explain why EXPR is not noexcept. */ +/* If EXPR is not noexcept, explain why. */ -void explain_not_noexcept (tree expr) +void +explain_not_noexcept (tree expr) { tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); - gcc_assert (fn); - if (DECL_P (fn)) + 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)); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 09fb4f3..f19794c 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3557,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 @@ -3593,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) { @@ -3649,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 @@ -3877,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); @@ -4717,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; diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index ecf55eb..711e3b7 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -409,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; @@ -503,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); @@ -727,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; @@ -980,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); @@ -1038,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; } @@ -1778,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) { @@ -1790,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; } diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index 08a6348..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; diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 13d5ded..80be40d 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "flags.h" #include "attribs.h" +#include "contracts.h" /* Debugging support. */ @@ -203,6 +204,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); @@ -1591,7 +1593,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); @@ -1820,6 +1824,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. */ @@ -3745,11 +3760,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. */ @@ -3794,6 +3857,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 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 62f8d80..ef8370f 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -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); @@ -1952,7 +1955,8 @@ build_trait_object (tree type, tsubst_flags_t complain) } /* [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) @@ -2460,21 +2464,13 @@ bool is_trivially_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/) { - /* In some cases, when producing errors is_xible_helper may not return - error_mark_node, so check if it looks like we've already emitted any - diagnostics to ensure we don't do so multiple times. */ - int errs = errorcount + sorrycount; - 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 && errs == (errorcount + sorrycount)) - { - gcc_assert (nt); - inform (location_of (nt), "%qE is non-trivial", nt); - } + if (explain && nt) + inform (location_of (nt), "%qE is non-trivial", nt); return !nt; } @@ -2487,9 +2483,6 @@ bool is_nothrow_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/) { - /* As with is_trivially_xible. */ - int errs = errorcount + sorrycount; - ++cp_noexcept_operand; tree expr = is_xible_helper (code, to, from, explain); --cp_noexcept_operand; @@ -2497,11 +2490,8 @@ is_nothrow_xible (enum tree_code code, tree to, tree from, return false; bool is_noexcept = expr_noexcept_p (expr, tf_none); - if (explain && errs == (errorcount + sorrycount)) - { - gcc_assert (!is_noexcept); - explain_not_noexcept (expr); - } + if (explain && !is_noexcept) + explain_not_noexcept (expr); return is_noexcept; } @@ -2601,12 +2591,10 @@ is_nothrow_convertible (tree from, tree to, bool explain/*=false*/) tree expr = is_convertible_helper (from, to, explain); if (expr == NULL_TREE || expr == error_mark_node) return false; + bool is_noexcept = expr_noexcept_p (expr, tf_none); - if (explain) - { - gcc_assert (!is_noexcept); - explain_not_noexcept (expr); - } + if (explain && !is_noexcept) + explain_not_noexcept (expr); return is_noexcept; } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 2f6a8ab..0404eae6 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -232,6 +232,7 @@ Classes used: #include "attribs.h" #include "intl.h" #include "langhooks.h" +#include "contracts.h" /* This TU doesn't need or want to see the networking. */ #define CODY_NETWORKING 0 #include "mapper-client.h" @@ -6560,8 +6561,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)) @@ -6651,11 +6658,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; @@ -7114,8 +7122,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)) @@ -7221,7 +7231,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; @@ -11164,6 +11174,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; diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index f5b36c9..ba62467 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -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; @@ -4626,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", @@ -4635,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"); @@ -4720,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; @@ -5347,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 @@ -5369,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; } diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 2fa736b..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. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 9e9cd9b..9f9bd56 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -601,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", @@ -2576,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); @@ -2611,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 @@ -2921,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 *); @@ -9504,11 +9506,12 @@ 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 @@ -9519,6 +9522,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, /* Restore the PEDANTIC flag. */ diagnostic_pop_diagnostics (global_dc, input_location); pedantic = saved_pedantic; + warn_long_long = saved_long_long; return expr; } @@ -11742,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; @@ -11754,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) { @@ -11797,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 @@ -11865,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; @@ -11891,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; @@ -12254,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 @@ -12278,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. */ @@ -12360,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, @@ -12456,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) { @@ -12513,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 @@ -12592,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 @@ -13138,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; } @@ -13190,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: @@ -13592,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); @@ -14618,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: @@ -14633,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); @@ -14719,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 { @@ -14733,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 @@ -14757,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, @@ -14866,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. @@ -14906,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); @@ -14989,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)) { @@ -15000,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; } @@ -15027,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 { @@ -15046,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. */ @@ -15083,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)); @@ -15093,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; @@ -15316,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: @@ -15360,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 (); @@ -15383,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; @@ -16047,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; } @@ -16297,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: @@ -16304,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. */ @@ -16323,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; } @@ -16392,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); @@ -16763,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 @@ -16776,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, @@ -16851,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); @@ -16859,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) @@ -16887,11 +17379,29 @@ cp_parser_decomposition_declaration (cp_parser *parser, else { prev = decl2; - DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl); - DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl); + 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 ()) @@ -17695,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 { @@ -27008,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); @@ -28827,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 @@ -28851,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) @@ -28869,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; } @@ -28955,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; @@ -32020,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)) { @@ -32035,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; } @@ -32882,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, @@ -36653,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 @@ -42543,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, @@ -42553,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; } @@ -42603,16 +43230,34 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) 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) @@ -42625,6 +43270,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) 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); @@ -42663,6 +43309,21 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) 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); @@ -42751,7 +43412,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) { cp_parser_error (parser, "%<map%> clause with map-type modifier " "other than %<always%>, %<close%>, " - "%<mapper%> or %<present%>"); + "%<iterator%>, %<mapper%> or %<present%>"); cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, @@ -42815,9 +43476,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) 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_ITERATORS (c) = iterators; last_new = c; } @@ -46070,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; @@ -46127,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; @@ -46193,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)); @@ -50956,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; } 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 71ae764..65de1cf 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "omp-general.h" #include "pretty-print-markup.h" +#include "contracts.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -6952,14 +6953,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; } @@ -7402,22 +7411,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; @@ -11445,7 +11454,8 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) #pragma GCC diagnostic ignored "-Wformat-diag" #endif bool list_p = new_level->list_p (); - if (list_p && !pp.has_flag (TDF_DETAILS)) + if ((list_p || TREE_CODE (tldcl) == TEMPLATE_FOR_STMT) + && !pp.has_flag (TDF_DETAILS)) /* Skip non-instantiations unless -details. */; else { @@ -11461,7 +11471,9 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) } for (int i = 0; i < tinst_depth; ++i) pp_space (&pp); - if (list_p) + 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); @@ -11575,7 +11587,9 @@ reopen_tinst_level (struct tinst_level *level) { last_ctx = ctx; pp_newline (&pp); - if (t->list_p ()) + 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); @@ -13973,9 +13987,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; @@ -13988,7 +14023,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); @@ -14003,8 +14039,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. */ @@ -14168,8 +14204,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); } @@ -15913,7 +15949,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) @@ -15930,6 +15969,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: @@ -18547,13 +18597,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) @@ -19330,6 +19384,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); @@ -19593,7 +19703,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; @@ -20480,6 +20591,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) { @@ -20493,6 +20616,10 @@ 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 @@ -20526,6 +20653,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) 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 (); @@ -20594,6 +20725,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 (); @@ -21211,7 +21343,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); @@ -22169,6 +22322,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. */ @@ -22385,12 +22543,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); @@ -22503,6 +22665,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)); } @@ -29041,6 +29210,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: @@ -29554,6 +29741,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)) @@ -32448,6 +32651,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/search.cc b/gcc/cp/search.cc index cea9f7c..77b5b1d 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "tree-inline.h" +#include "contracts.h" static int is_subobject_of_p (tree, tree); static tree dfs_lookup_base (tree, void *); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 52ecac4..1937ace 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "predict.h" #include "memmodel.h" #include "gimplify.h" +#include "contracts.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -677,7 +678,7 @@ do_poplevel (tree stmt_list) /* Begin a new scope. */ -static tree +tree do_pushlevel (scope_kind sk) { tree ret = push_stmt_list (); @@ -1854,6 +1855,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 @@ -3992,9 +4008,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); @@ -4490,6 +4512,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. */ @@ -4504,7 +4537,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. */ @@ -4550,7 +4591,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)) @@ -7745,7 +7786,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)) { @@ -8997,6 +9045,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* 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; @@ -9900,6 +9955,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; @@ -12598,11 +12658,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; @@ -12630,6 +12693,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, @@ -12641,6 +12705,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, @@ -12890,9 +12961,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 @@ -12909,8 +12980,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); @@ -12926,17 +12995,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); } @@ -13631,10 +13711,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 and __builtin_type_order are 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) \ @@ -13739,6 +13820,27 @@ same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2) (non_reference (to), non_reference (from)))); } +/* Helper for finish_trait_expr and tsubst_expr. Handle + CPTK_STRUCTURED_BINDING_SIZE in possibly SFINAE-friendly + way. */ + +tree +finish_structured_binding_size (location_t loc, tree type, + tsubst_flags_t complain) +{ + 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. */ tree @@ -13751,7 +13853,7 @@ 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) { @@ -13868,9 +13970,22 @@ 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: + 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: - break; + 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) @@ -13901,20 +14016,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 if (kind == CPTK_TYPE_ORDER) - val = type_order_value (type1, type2); - else - val = (trait_expr_value (kind, type1, type2) - ? boolean_true_node : boolean_false_node); - + tree val = (trait_expr_value (kind, type1, type2) + ? boolean_true_node : boolean_false_node); return maybe_wrap_with_location (val, loc); } @@ -14111,7 +14214,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/tree.cc b/gcc/cp/tree.cc index d56d73f..e354da0 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -1186,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) { @@ -6394,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 f592894..ccfe50d 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -3973,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) @@ -3987,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)) @@ -4066,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; @@ -4149,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. */ @@ -4287,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, diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index faaf1df..d77de92 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -281,15 +281,96 @@ 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. |