diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 262 | ||||
-rw-r--r-- | gcc/cp/call.cc | 27 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 9 | ||||
-rw-r--r-- | gcc/cp/constraint.cc | 3 | ||||
-rw-r--r-- | gcc/cp/cp-objcp-common.cc | 1 | ||||
-rw-r--r-- | gcc/cp/cp-trait.def | 1 | ||||
-rw-r--r-- | gcc/cp/cp-tree.def | 5 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 49 | ||||
-rw-r--r-- | gcc/cp/cxx-pretty-print.cc | 23 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 528 | ||||
-rw-r--r-- | gcc/cp/decl2.cc | 8 | ||||
-rw-r--r-- | gcc/cp/error.cc | 23 | ||||
-rw-r--r-- | gcc/cp/lambda.cc | 40 | ||||
-rw-r--r-- | gcc/cp/lex.cc | 43 | ||||
-rw-r--r-- | gcc/cp/mangle.cc | 16 | ||||
-rw-r--r-- | gcc/cp/mapper-client.cc | 46 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 23 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 6 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 705 | ||||
-rw-r--r-- | gcc/cp/parser.h | 6 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 611 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 140 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 11 | ||||
-rw-r--r-- | gcc/cp/typeck.cc | 2 |
24 files changed, 2256 insertions, 332 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8e9b8ea..8dc1168 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,265 @@ +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 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/constexpr.cc b/gcc/cp/constexpr.cc index b8ac454..223240a 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -11615,12 +11615,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)) @@ -12473,6 +12475,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 cbdfafc..4b20b79 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3304,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/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 fb8e0d8..55e8e07 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -476,6 +476,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) @@ -1557,6 +1558,13 @@ enum cp_lambda_default_capture_mode_type { #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)) @@ -1973,6 +1981,8 @@ struct GTY(()) saved_scope { of consteval if statement. Also set while processing an immediate invocation. */ BOOL_BITFIELD consteval_if_p : 1; + /* Nonzero if we are parsing the substatement of expansion-statement. */ + BOOL_BITFIELD expansion_stmt : 1; int unevaluated_operand; int inhibit_evaluation_warnings; @@ -2046,6 +2056,7 @@ extern GTY(()) struct saved_scope *scope_chain; #define in_discarded_stmt scope_chain->discarded_stmt #define in_consteval_if_p scope_chain->consteval_if_p +#define in_expansion_stmt scope_chain->expansion_stmt #define current_ref_temp_count scope_chain->ref_temp_count @@ -2330,7 +2341,8 @@ enum languages { lang_c, lang_cplusplus }; /* Nonzero if NODE, a TYPE, has no name for linkage purposes. */ #define TYPE_UNNAMED_P(NODE) \ (TYPE_ANON_P (NODE) \ - && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE))) + && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \ + && !enum_with_enumerator_for_linkage_p (NODE)) /* The _DECL for this _TYPE. */ #define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE))) @@ -5691,6 +5703,19 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) #define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_5 (RANGE_FOR_STMT_CHECK (NODE)) +/* TEMPLATE_FOR_STMT accessors. These give access to the declarator, + expression, body, and scope of the statement, respectively. */ +#define TEMPLATE_FOR_DECL(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 0) +#define TEMPLATE_FOR_EXPR(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 1) +#define TEMPLATE_FOR_BODY(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 2) +#define TEMPLATE_FOR_SCOPE(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 3) +#define TEMPLATE_FOR_INIT_STMT(NODE) \ + TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 4) + /* STMT_EXPR accessor. */ #define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) @@ -6802,9 +6827,11 @@ struct GTY((chain_next ("%h.next"))) tinst_level { /* The original node. TLDCL can be a DECL (for a function or static data member), a TYPE (for a class), depending on what we were - asked to instantiate, or a TREE_LIST with the template as PURPOSE - and the template args as VALUE, if we are substituting for - overload resolution. In all these cases, TARGS is NULL. + asked to instantiate, a TEMPLATE_FOR_STMT (for instantiation + of expansion stmt body outside of templates) or a TREE_LIST with + the template as PURPOSE and the template args as VALUE, if we are + substituting for overload resolution. In all these cases, TARGS + is NULL. However, to avoid creating TREE_LIST objects for substitutions if we can help, we store PURPOSE and VALUE in TLDCL and TARGS, respectively. So TLDCL stands for TREE_LIST or DECL (the @@ -7278,6 +7305,7 @@ extern void omp_declare_variant_finalize (tree, tree); struct cp_decomp { tree decl; unsigned int count; }; extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr); extern tree lookup_decomp_type (tree); +HOST_WIDE_INT cp_decomp_size (location_t, tree, tsubst_flags_t); extern bool cp_finish_decomp (tree, cp_decomp *, bool = false); extern int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); @@ -7298,6 +7326,7 @@ extern tree xref_tag (tag_types, tree, bool tpl_header_p = false); extern void xref_basetypes (tree, tree); extern tree start_enum (tree, tree, tree, tree, bool, bool *); +extern bool enum_with_enumerator_for_linkage_p (tree); extern void finish_enum_value_list (tree); extern void finish_enum (tree); extern tree build_enumerator (tree, tree, tree, tree, location_t); @@ -7760,8 +7789,12 @@ extern tree clone_attrs (tree); extern bool maybe_clone_body (tree); /* In parser.cc */ +extern tree cp_build_range_for_decls (location_t, tree, tree *, bool); extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, tree, bool); +extern tree build_range_temp (tree); +extern tree cp_perform_range_for_lookup (tree, tree *, tree *, + tsubst_flags_t = tf_warning_or_error); extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &, bool); @@ -7774,6 +7807,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); @@ -7978,6 +8013,7 @@ extern tree add_to_template_args (tree, tree); extern tree add_outermost_template_args (tree, tree); extern tree add_extra_args (tree, tree, tsubst_flags_t, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); +extern void finish_expansion_stmt (tree, tree, tsubst_flags_t, tree); /* in rtti.cc */ /* A vector of all tinfo decls that haven't been emitted yet. */ @@ -8078,6 +8114,7 @@ public: extern int stmts_are_full_exprs_p (void); extern void init_cp_semantics (void); extern tree do_poplevel (tree); +extern tree do_pushlevel (scope_kind); extern void break_maybe_infinite_loop (void); extern void add_decl_expr (tree); extern tree maybe_cleanup_point_expr_void (tree); @@ -8104,7 +8141,7 @@ extern void find_range_for_decls (tree[3]); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); extern void finish_range_for_decl (tree, tree, tree); -extern void finish_range_for_stmt (tree); +extern tree begin_template_for_scope (tree *); extern tree finish_break_stmt (void); extern tree finish_continue_stmt (void); extern tree begin_switch_stmt (void); @@ -8257,6 +8294,7 @@ extern void finish_static_assert (tree, tree, location_t, 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); @@ -8301,6 +8339,7 @@ extern void record_lambda_scope (tree lambda); extern void record_lambda_scope_discriminator (tree lambda); extern void record_lambda_scope_sig_discriminator (tree lambda, tree fn); extern tree start_lambda_function (tree fn, tree lambda_expr); +extern void push_capture_proxies (tree, bool = false); extern void finish_lambda_function (tree body); extern bool regenerated_lambda_fn_p (tree); extern tree lambda_regenerating_args (tree); 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 8122fca..140cc9b 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -572,9 +572,9 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) ent->in_stmt_expr = true; break; case sk_block: - if (level_for_constexpr_if (bl->level_chain)) + if (level_for_constexpr_if (obl)) ent->in_constexpr_if = true; - else if (level_for_consteval_if (bl->level_chain)) + else if (level_for_consteval_if (obl)) ent->in_consteval_if = true; break; default: @@ -4336,7 +4336,19 @@ finish_case_label (location_t loc, tree low_value, tree high_value) tree label; /* For templates, just add the case label; we'll do semantic - analysis at instantiation-time. */ + analysis at instantiation-time. But diagnose case labels + in expansion statements with switch outside of it here. */ + if (in_expansion_stmt) + for (cp_binding_level *b = current_binding_level; + b != switch_stack->level; b = b->level_chain) + if (b->kind == sk_template_for && b->this_entity) + { + auto_diagnostic_group d; + error ("jump to case label"); + inform (EXPR_LOCATION (b->this_entity), + " enters %<template for%> statement"); + return error_mark_node; + } label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node); return add_stmt (build_case_label (low_value, high_value, label)); } @@ -9633,13 +9645,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 +9669,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 +9683,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 +9706,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 +9762,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 +9772,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 +9788,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 +9894,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 +10078,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 +10106,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 +10132,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 +10153,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 +10192,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 +10238,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 +10302,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 +10336,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 +10448,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 +10471,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 +10480,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 +10493,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 +10527,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 +13017,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 +13106,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 +13125,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 +15384,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 +18230,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 +18472,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 ()); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 2bbc618..c6c9dfc 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -6229,6 +6229,7 @@ cp_warn_deprecated_use_scopes (tree scope) bool decl_dependent_p (tree decl) { + tree orig_decl = decl; if (DECL_FUNCTION_SCOPE_P (decl) || TREE_CODE (decl) == CONST_DECL || TREE_CODE (decl) == USING_DECL @@ -6240,6 +6241,13 @@ decl_dependent_p (tree decl) if (LAMBDA_FUNCTION_P (decl) && dependent_type_p (DECL_CONTEXT (decl))) return true; + /* for-range-declaration of expansion statement as well as variable + declarations in the expansion statement body when the expansion statement + is not inside a template still need to be treated as dependent during + parsing. When the body is instantiated, in_expansion_stmt will be already + false. */ + if (VAR_P (orig_decl) && in_expansion_stmt && decl == current_function_decl) + return true; return false; } 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/lambda.cc b/gcc/cp/lambda.cc index c798967..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); @@ -1784,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) { @@ -1796,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 b7d2ac6..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]; @@ -384,47 +384,42 @@ cxx_init (void) if (IDENTIFIER_KEYWORD_P (id) /* Don't register keywords with spaces. */ && IDENTIFIER_POINTER (id)[IDENTIFIER_LENGTH (id) - 1] != ' ') - cpp_lookup (parse_in, - (const unsigned char *) IDENTIFIER_POINTER (id), - IDENTIFIER_LENGTH (id))->flags |= NODE_WARN; + cpp_warn (parse_in, IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id)); } - auto warn_on = [] (const char *name) { - cpp_lookup (parse_in, (const unsigned char *) name, - strlen (name))->flags |= NODE_WARN; - }; if (cxx_dialect >= cxx11) { - warn_on ("final"); - warn_on ("override"); - warn_on ("noreturn"); + cpp_warn (parse_in, "final"); + cpp_warn (parse_in, "override"); + cpp_warn (parse_in, "noreturn"); if (cxx_dialect < cxx26) - warn_on ("carries_dependency"); + cpp_warn (parse_in, "carries_dependency"); } if (cxx_dialect >= cxx14) - warn_on ("deprecated"); + cpp_warn (parse_in, "deprecated"); if (cxx_dialect >= cxx17) { - warn_on ("fallthrough"); - warn_on ("maybe_unused"); - warn_on ("nodiscard"); + cpp_warn (parse_in, "fallthrough"); + cpp_warn (parse_in, "maybe_unused"); + cpp_warn (parse_in, "nodiscard"); } if (cxx_dialect >= cxx20) { - warn_on ("likely"); - warn_on ("unlikely"); - warn_on ("no_unique_address"); + cpp_warn (parse_in, "likely"); + cpp_warn (parse_in, "unlikely"); + cpp_warn (parse_in, "no_unique_address"); } if (flag_modules) { - warn_on ("import"); - warn_on ("module"); + cpp_warn (parse_in, "import"); + cpp_warn (parse_in, "module"); } if (cxx_dialect >= cxx23) - warn_on ("assume"); + cpp_warn (parse_in, "assume"); if (cxx_dialect >= cxx26) { - warn_on ("replaceable_if_eligible"); - warn_on ("trivially_relocatable_if_eligible"); + cpp_warn (parse_in, "replaceable_if_eligible"); + cpp_warn (parse_in, "trivially_relocatable_if_eligible"); } } diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index fd69099..f48cb22 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -203,6 +203,7 @@ static void write_conversion_operator_name (const tree); static void write_source_name (tree); static void write_literal_operator_name (tree); static void write_unnamed_type_name (const tree); +static void write_unnamed_enum_name (const tree); static void write_closure_type_name (const tree); static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *, const unsigned int); @@ -1591,7 +1592,9 @@ write_unqualified_name (tree decl) tree type = TREE_TYPE (decl); if (TREE_CODE (decl) == TYPE_DECL - && TYPE_UNNAMED_P (type)) + && enum_with_enumerator_for_linkage_p (type)) + write_unnamed_enum_name (type); + else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type)) write_unnamed_type_name (type); else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) write_closure_type_name (type); @@ -1820,6 +1823,17 @@ write_unnamed_type_name (const tree type) write_compact_number (discriminator); } +/* <unnamed-enum-name> ::= Ue <underlying type> <enumerator source-name> */ + +static void +write_unnamed_enum_name (const tree type) +{ + MANGLE_TRACE_TREE ("unnamed-enum-name", type); + write_string ("Ue"); + write_type (ENUM_UNDERLYING_TYPE (type)); + write_source_name (DECL_NAME (TREE_VALUE (TYPE_VALUES (type)))); +} + /* ABI issue #47: if a function template parameter is not "natural" for its argument we must mangle the parameter. */ 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/name-lookup.cc b/gcc/cp/name-lookup.cc index f5b36c9..4614790 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3351,8 +3351,11 @@ 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))) { /* Go to where the parms should be and see if we find them there. */ @@ -3408,7 +3411,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 +4631,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 +4641,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 +4727,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 +5356,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 +5379,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 a8c54c7..d66b658 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", @@ -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 @@ -11875,12 +11877,20 @@ 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; + /* 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); @@ -11902,8 +11912,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; @@ -12292,6 +12305,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. */ @@ -12482,6 +12502,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) { @@ -12539,6 +12563,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 @@ -12618,6 +12646,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 @@ -13164,6 +13265,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; } @@ -13216,6 +13322,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: @@ -13618,6 +13734,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); @@ -14644,6 +14767,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: @@ -14659,56 +14849,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); @@ -14745,7 +14893,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 { @@ -14759,7 +14907,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 @@ -14783,15 +14931,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, @@ -14892,6 +15047,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. @@ -14932,56 +15170,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); @@ -15015,8 +15211,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)) { @@ -15026,8 +15224,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; } @@ -15053,16 +15252,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 { @@ -15072,13 +15271,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. */ @@ -15109,7 +15315,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)); @@ -15119,11 +15325,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; @@ -15342,6 +15548,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: @@ -15386,7 +15769,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 (); @@ -15409,6 +15793,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; @@ -16843,7 +17228,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 @@ -16856,21 +17241,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, @@ -16931,7 +17340,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); @@ -16939,6 +17348,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) @@ -16967,11 +17377,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 ()) @@ -36746,7 +37174,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 @@ -46300,8 +46732,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; @@ -46357,8 +46797,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; @@ -46423,6 +46863,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)); 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 acfeb81..bb2d0b4 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11453,7 +11453,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 { @@ -11469,7 +11470,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); @@ -11583,7 +11586,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); @@ -13981,9 +13986,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, else if (is_capture_proxy (parm_pack)) { arg_pack = retrieve_local_specialization (parm_pack); + if (DECL_DECOMPOSITION_P (arg_pack)) + { + orig_arg = arg_pack; + goto expand_sb_pack; + } if (DECL_PACK_P (arg_pack)) arg_pack = NULL_TREE; } + else if (DECL_DECOMPOSITION_P (parm_pack)) + { + orig_arg = retrieve_local_specialization (parm_pack); + expand_sb_pack: + gcc_assert (DECL_DECOMPOSITION_P (orig_arg)); + if (TREE_TYPE (orig_arg) == error_mark_node) + return error_mark_node; + gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg)); + arg_pack = DECL_VALUE_EXPR (orig_arg); + tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2); + if (TREE_VEC_LENGTH (vec)) + memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2), + TREE_VEC_LENGTH (vec) * sizeof (tree)); + arg_pack = make_node (NONTYPE_ARGUMENT_PACK); + ARGUMENT_PACK_ARGS (arg_pack) = vec; + } else { int idx; @@ -13996,7 +14022,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, arg_pack = NULL_TREE; } - orig_arg = arg_pack; + if (orig_arg == NULL_TREE) + orig_arg = arg_pack; if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT) arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack); @@ -14011,8 +14038,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, if (arg_pack) { - int my_len = - TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); + int my_len + = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); /* Don't bother trying to do a partial substitution with incomplete packs; we'll try again after deduction. */ @@ -14176,8 +14203,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, /* Update the corresponding argument. */ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) - TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) = - TREE_TYPE (pack); + TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) + = TREE_TYPE (pack); else TREE_VEC_ELT (args, idx) = TREE_TYPE (pack); } @@ -15921,7 +15948,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, tsubst_flags_t tcomplain = complain; if (VAR_P (t)) tcomplain |= tf_tst_ok; - type = tsubst (type, args, tcomplain, in_decl); + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + type = NULL_TREE; + else + type = tsubst (type, args, tcomplain, in_decl); /* Substituting the type might have recursively instantiated this same alias (c++/86171). */ if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl) @@ -15938,6 +15968,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, { DECL_INITIALIZED_P (r) = 0; DECL_TEMPLATE_INSTANTIATED (r) = 0; + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = r; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = r; + } if (TREE_CODE (type) == FUNCTION_TYPE) { /* It may seem that this case cannot occur, since: @@ -18555,13 +18596,17 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); - if (TREE_CODE (v) == ARRAY_REF - && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + if ((TREE_CODE (v) == ARRAY_REF + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + || (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))) { + v = (TREE_CODE (v) == ARRAY_REF + ? TREE_OPERAND (v, 0) : TREE_VEC_ELT (v, 0)); cp_decomp decomp_d = { NULL_TREE, 0 }; - tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain); + tree d = tsubst_decl (v, args, complain); maybe_push_decl (d); - d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain, + d = tsubst_decomp_names (d, v, args, complain, in_decl, &decomp_d); decomp = true; if (d == error_mark_node) @@ -19338,6 +19383,62 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_do_stmt (tmp, stmt, false, 0, false); break; + case TEMPLATE_FOR_STMT: + { + tree init; + stmt = build_stmt (EXPR_LOCATION (t), TEMPLATE_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + TEMPLATE_FOR_SCOPE (stmt) = begin_template_for_scope (&init); + TEMPLATE_FOR_INIT_STMT (stmt) = init; + RECUR (TEMPLATE_FOR_INIT_STMT (t)); + TEMPLATE_FOR_EXPR (stmt) = RECUR (TEMPLATE_FOR_EXPR (t)); + if (processing_template_decl) + { + tree orig_decl = TEMPLATE_FOR_DECL (t); + if (TREE_CODE (orig_decl) == TREE_VEC) + orig_decl = TREE_VEC_ELT (orig_decl, 0); + tree decl = tsubst (orig_decl, args, complain, in_decl); + maybe_push_decl (decl); + + cp_decomp decomp_d, *decomp = NULL; + if (DECL_DECOMPOSITION_P (decl)) + { + decomp = &decomp_d; + decl = tsubst_decomp_names (decl, orig_decl, args, + complain, in_decl, decomp); + if (decl != error_mark_node) + { + tree v = make_tree_vec (decomp->count + 1); + TREE_VEC_ELT (v, 0) = decl; + decl = decomp->decl; + for (unsigned i = 0; i < decomp->count; ++i) + { + TREE_VEC_ELT (v, decomp->count - i) = decl; + decl = DECL_CHAIN (decl); + } + decl = v; + } + } + TEMPLATE_FOR_DECL (stmt) = decl; + TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init); + add_stmt (stmt); + TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block); + bool prev = note_iteration_stmt_body_start (); + RECUR (TEMPLATE_FOR_BODY (t)); + note_iteration_stmt_body_end (prev); + TEMPLATE_FOR_BODY (stmt) + = do_poplevel (TEMPLATE_FOR_BODY (stmt)); + } + else + { + TEMPLATE_FOR_DECL (stmt) = TEMPLATE_FOR_DECL (t); + TEMPLATE_FOR_BODY (stmt) = TEMPLATE_FOR_BODY (t); + finish_expansion_stmt (stmt, args, complain, in_decl); + } + add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (stmt))); + } + break; + case IF_STMT: stmt = begin_if_stmt (); IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); @@ -20489,6 +20590,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree fntype = static_fn_type (oldfn); + begin_scope (sk_lambda, NULL_TREE); + + /* Like in cp_parser_lambda_expression, we need to bring the captures + into the lambda scope. */ + tree ns = decl_namespace_context (type); + push_nested_namespace (ns); + push_nested_class (type); + tree dummy_fco = maybe_add_dummy_lambda_op (r); + pop_nested_class (); + pop_nested_namespace (ns); + push_capture_proxies (r, /*early_p=*/true); + tree saved_ctp = current_template_parms; if (oldtmpl) { @@ -20502,6 +20615,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 @@ -20535,6 +20652,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 (); @@ -20603,6 +20724,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } out: + pop_bindings_and_leave_scope (); finish_struct (type, /*attr*/NULL_TREE); insert_pending_capture_proxies (); @@ -21220,7 +21342,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ++c_inhibit_evaluation_warnings; /* We only want to compute the number of arguments. */ if (PACK_EXPANSION_P (op)) - expanded = tsubst_pack_expansion (op, args, complain, in_decl); + { + expanded = NULL_TREE; + if (DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op))) + { + tree d = PACK_EXPANSION_PATTERN (op); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + if (TREE_CODE (d) == TREE_VEC) + { + tree b = TREE_VEC_ELT (d, 0); + if (!type_dependent_expression_p_push (b)) + { + expanded = void_node; + len = TREE_VEC_LENGTH (d) - 2; + } + } + } + } + if (!expanded) + expanded = tsubst_pack_expansion (op, args, complain, in_decl); + } else expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op), args, complain, in_decl); @@ -22512,6 +22655,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)); } @@ -29050,6 +29200,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: @@ -29563,6 +29731,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)) @@ -32457,6 +32641,405 @@ 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; + if (sz == 0) + { + error_at (loc, "empty structured binding"); + 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; + 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, &this_decomp); + 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/semantics.cc b/gcc/cp/semantics.cc index 0c7788d..26709c7 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -677,7 +677,7 @@ do_poplevel (tree stmt_list) /* Begin a new scope. */ -static tree +tree do_pushlevel (scope_kind sk) { tree ret = push_stmt_list (); @@ -1854,6 +1854,21 @@ finish_range_for_decl (tree range_for_stmt, tree decl, tree expr) RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block); } +/* Begin the scope of an expansion-statement. */ + +tree +begin_template_for_scope (tree *init) +{ + tree scope = do_pushlevel (sk_template_for); + + if (processing_template_decl) + *init = push_stmt_list (); + else + *init = NULL_TREE; + + return scope; +} + /* Finish a break-statement. */ tree @@ -4496,6 +4511,17 @@ baselink_for_fns (tree fns) return build_baselink (conv_path, access_path, fns, /*optype=*/NULL_TREE); } +/* Returns true iff we are currently parsing a lambda-declarator. */ + +static bool +parsing_lambda_declarator () +{ + cp_binding_level *b = current_binding_level; + while (b->kind == sk_template_parms || b->kind == sk_function_parms) + b = b->level_chain; + return b->kind == sk_lambda; +} + /* Returns true iff DECL is a variable from a function outside the current one. */ @@ -4510,7 +4536,15 @@ outer_var_p (tree decl) /* Don't get confused by temporaries. */ && DECL_NAME (decl) && (DECL_CONTEXT (decl) != current_function_decl - || parsing_nsdmi ())); + || parsing_nsdmi () + /* Also consider captures as outer vars if we are in + decltype in a lambda declarator as in: + auto l = [j=0]() -> decltype((j)) { ... } + for the sake of finish_decltype_type. + + (Similar issue also affects non-lambdas, but vexing parse + makes it more difficult to handle than lambdas.) */ + || parsing_lambda_declarator ())); } /* As above, but also checks that DECL is automatic. */ @@ -4556,7 +4590,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use) if (!mark_used (decl, complain)) return error_mark_node; - if (parsing_nsdmi ()) + if (parsing_nsdmi () || parsing_lambda_declarator ()) containing_function = NULL_TREE; if (containing_function && LAMBDA_FUNCTION_P (containing_function)) @@ -12926,9 +12960,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, } else { - if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr)) - && current_function_decl - && LAMBDA_FUNCTION_P (current_function_decl)) + tree decl = STRIP_REFERENCE_REF (expr); + tree lam = current_lambda_expr (); + if (lam && outer_automatic_var_p (decl)) { /* [expr.prim.id.unqual]/3: If naming the entity from outside of an unevaluated operand within S would refer to an entity captured by @@ -12945,8 +12979,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, local variable inside decltype, not just decltype((x)) (PR83167). And we don't handle nested lambdas properly, where we need to consider the outer lambdas as well (PR112926). */ - tree decl = STRIP_REFERENCE_REF (expr); - tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); tree cap = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK, LOOK_want::HIDDEN_LAMBDA); @@ -12962,17 +12994,28 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, if (type && !TYPE_REF_P (type)) { - tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl)); - if (WILDCARD_TYPE_P (non_reference (obtype))) - /* We don't know what the eventual obtype quals will be. */ - goto dependent; - auto direct_type = [](tree t){ - if (INDIRECT_TYPE_P (t)) - return TREE_TYPE (t); - return t; - }; - int const quals = cp_type_quals (type) - | cp_type_quals (direct_type (obtype)); + int quals; + if (current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl) + && DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl)) + { + tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl)); + if (WILDCARD_TYPE_P (non_reference (obtype))) + /* We don't know what the eventual obtype quals will be. */ + goto dependent; + auto direct_type = [](tree t){ + if (INDIRECT_TYPE_P (t)) + return TREE_TYPE (t); + return t; + }; + quals = (cp_type_quals (type) + | cp_type_quals (direct_type (obtype))); + } + else + /* We are in the parameter clause, trailing return type, or + the requires clause and have no relevant c_f_decl yet. */ + quals = (LAMBDA_EXPR_CONST_QUAL_P (lam) + ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED); type = cp_build_qualified_type (type, quals); type = build_reference_type (type); } @@ -13667,10 +13710,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_DEDUCIBLE: return type_targs_deducible_from (type1, type2); - /* __array_rank 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) \ @@ -13775,6 +13819,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 @@ -13787,7 +13852,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) { @@ -13904,9 +13969,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) @@ -13937,20 +14015,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) gcc_unreachable (); } - tree val; - if (kind == CPTK_RANK) - { - size_t rank = 0; - for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1)) - ++rank; - val = build_int_cst (size_type_node, rank); - } - else 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); } 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..41a3f4c 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -4287,7 +4287,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, |