diff options
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r-- | gcc/cp/pt.cc | 676 |
1 files changed, 637 insertions, 39 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 71ae764..65de1cf 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "omp-general.h" #include "pretty-print-markup.h" +#include "contracts.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -6952,14 +6953,22 @@ convert_nontype_argument_function (tree type, tree expr, { auto_diagnostic_group d; location_t loc = cp_expr_loc_or_input_loc (expr); - error_at (loc, "%qE is not a valid template argument for type %qT", - expr, type); - if (TYPE_PTR_P (type)) - inform (loc, "it must be the address of a function " - "with external linkage"); + tree c; + if (cxx_dialect >= cxx17 + && (c = cxx_constant_value (fn), + c == error_mark_node)) + ; else - inform (loc, "it must be the name of a function with " - "external linkage"); + { + error_at (loc, "%qE is not a valid template argument for " + "type %qT", expr, type); + if (TYPE_PTR_P (type)) + inform (loc, "it must be the address of a function " + "with external linkage"); + else + inform (loc, "it must be the name of a function with " + "external linkage"); + } } return NULL_TREE; } @@ -7402,22 +7411,22 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) /* Null pointer values are OK in C++11. */; else { - if (VAR_P (expr)) - { - if (complain & tf_error) - error ("%qD is not a valid template argument " - "because %qD is a variable, not the address of " - "a variable", expr, expr); - return true; - } + tree c; + if (!(complain & tf_error)) + ; + else if (cxx_dialect >= cxx17 + && (c = cxx_constant_value (expr), + c == error_mark_node)) + ; + else if (VAR_P (expr)) + error ("%qD is not a valid template argument " + "because %qD is a variable, not the address of " + "a variable", expr, expr); else - { - if (complain & tf_error) - error ("%qE is not a valid template argument for %qT " - "because it is not the address of a variable", - expr, type); - return true; - } + error ("%qE is not a valid template argument for %qT " + "because it is not the address of a variable", + expr, type); + return true; } } return false; @@ -11445,7 +11454,8 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) #pragma GCC diagnostic ignored "-Wformat-diag" #endif bool list_p = new_level->list_p (); - if (list_p && !pp.has_flag (TDF_DETAILS)) + if ((list_p || TREE_CODE (tldcl) == TEMPLATE_FOR_STMT) + && !pp.has_flag (TDF_DETAILS)) /* Skip non-instantiations unless -details. */; else { @@ -11461,7 +11471,9 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) } for (int i = 0; i < tinst_depth; ++i) pp_space (&pp); - if (list_p) + if (TREE_CODE (tldcl) == TEMPLATE_FOR_STMT) + pp_printf (&pp, "I template for"); + else if (list_p) pp_printf (&pp, "S %S", new_level->get_node ()); else pp_printf (&pp, "I %D", tldcl); @@ -11575,7 +11587,9 @@ reopen_tinst_level (struct tinst_level *level) { last_ctx = ctx; pp_newline (&pp); - if (t->list_p ()) + if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT) + pp_printf (&pp, "RI template for"); + else if (t->list_p ()) pp_printf (&pp, "RS %S", ctx); else pp_printf (&pp, "RI %D", ctx); @@ -13973,9 +13987,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, else if (is_capture_proxy (parm_pack)) { arg_pack = retrieve_local_specialization (parm_pack); + if (DECL_DECOMPOSITION_P (arg_pack)) + { + orig_arg = arg_pack; + goto expand_sb_pack; + } if (DECL_PACK_P (arg_pack)) arg_pack = NULL_TREE; } + else if (DECL_DECOMPOSITION_P (parm_pack)) + { + orig_arg = retrieve_local_specialization (parm_pack); + expand_sb_pack: + gcc_assert (DECL_DECOMPOSITION_P (orig_arg)); + if (TREE_TYPE (orig_arg) == error_mark_node) + return error_mark_node; + gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg)); + arg_pack = DECL_VALUE_EXPR (orig_arg); + tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2); + if (TREE_VEC_LENGTH (vec)) + memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2), + TREE_VEC_LENGTH (vec) * sizeof (tree)); + arg_pack = make_node (NONTYPE_ARGUMENT_PACK); + ARGUMENT_PACK_ARGS (arg_pack) = vec; + } else { int idx; @@ -13988,7 +14023,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, arg_pack = NULL_TREE; } - orig_arg = arg_pack; + if (orig_arg == NULL_TREE) + orig_arg = arg_pack; if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT) arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack); @@ -14003,8 +14039,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, if (arg_pack) { - int my_len = - TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); + int my_len + = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)); /* Don't bother trying to do a partial substitution with incomplete packs; we'll try again after deduction. */ @@ -14168,8 +14204,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, /* Update the corresponding argument. */ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)) - TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) = - TREE_TYPE (pack); + TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) + = TREE_TYPE (pack); else TREE_VEC_ELT (args, idx) = TREE_TYPE (pack); } @@ -15913,7 +15949,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, tsubst_flags_t tcomplain = complain; if (VAR_P (t)) tcomplain |= tf_tst_ok; - type = tsubst (type, args, tcomplain, in_decl); + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + type = NULL_TREE; + else + type = tsubst (type, args, tcomplain, in_decl); /* Substituting the type might have recursively instantiated this same alias (c++/86171). */ if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl) @@ -15930,6 +15969,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain, { DECL_INITIALIZED_P (r) = 0; DECL_TEMPLATE_INSTANTIATED (r) = 0; + if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t)) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = r; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = r; + } if (TREE_CODE (type) == FUNCTION_TYPE) { /* It may seem that this case cannot occur, since: @@ -18547,13 +18597,17 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); - if (TREE_CODE (v) == ARRAY_REF - && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + if ((TREE_CODE (v) == ARRAY_REF + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + || (TREE_CODE (v) == TREE_VEC + && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))) { + v = (TREE_CODE (v) == ARRAY_REF + ? TREE_OPERAND (v, 0) : TREE_VEC_ELT (v, 0)); cp_decomp decomp_d = { NULL_TREE, 0 }; - tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain); + tree d = tsubst_decl (v, args, complain); maybe_push_decl (d); - d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain, + d = tsubst_decomp_names (d, v, args, complain, in_decl, &decomp_d); decomp = true; if (d == error_mark_node) @@ -19330,6 +19384,62 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_do_stmt (tmp, stmt, false, 0, false); break; + case TEMPLATE_FOR_STMT: + { + tree init; + stmt = build_stmt (EXPR_LOCATION (t), TEMPLATE_FOR_STMT, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); + TEMPLATE_FOR_SCOPE (stmt) = begin_template_for_scope (&init); + TEMPLATE_FOR_INIT_STMT (stmt) = init; + RECUR (TEMPLATE_FOR_INIT_STMT (t)); + TEMPLATE_FOR_EXPR (stmt) = RECUR (TEMPLATE_FOR_EXPR (t)); + if (processing_template_decl) + { + tree orig_decl = TEMPLATE_FOR_DECL (t); + if (TREE_CODE (orig_decl) == TREE_VEC) + orig_decl = TREE_VEC_ELT (orig_decl, 0); + tree decl = tsubst (orig_decl, args, complain, in_decl); + maybe_push_decl (decl); + + cp_decomp decomp_d, *decomp = NULL; + if (DECL_DECOMPOSITION_P (decl)) + { + decomp = &decomp_d; + decl = tsubst_decomp_names (decl, orig_decl, args, + complain, in_decl, decomp); + if (decl != error_mark_node) + { + tree v = make_tree_vec (decomp->count + 1); + TREE_VEC_ELT (v, 0) = decl; + decl = decomp->decl; + for (unsigned i = 0; i < decomp->count; ++i) + { + TREE_VEC_ELT (v, decomp->count - i) = decl; + decl = DECL_CHAIN (decl); + } + decl = v; + } + } + TEMPLATE_FOR_DECL (stmt) = decl; + TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init); + add_stmt (stmt); + TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block); + bool prev = note_iteration_stmt_body_start (); + RECUR (TEMPLATE_FOR_BODY (t)); + note_iteration_stmt_body_end (prev); + TEMPLATE_FOR_BODY (stmt) + = do_poplevel (TEMPLATE_FOR_BODY (stmt)); + } + else + { + TEMPLATE_FOR_DECL (stmt) = TEMPLATE_FOR_DECL (t); + TEMPLATE_FOR_BODY (stmt) = TEMPLATE_FOR_BODY (t); + finish_expansion_stmt (stmt, args, complain, in_decl); + } + add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (stmt))); + } + break; + case IF_STMT: stmt = begin_if_stmt (); IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); @@ -19593,7 +19703,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_static_assert (condition, message, STATIC_ASSERT_SOURCE_LOCATION (t), - /*member_p=*/false, /*show_expr_p=*/true); + /*member_p=*/false, /*show_expr_p=*/true, + CONSTEVAL_BLOCK_P (t)); } break; @@ -20480,6 +20591,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree fntype = static_fn_type (oldfn); + begin_scope (sk_lambda, NULL_TREE); + + /* Like in cp_parser_lambda_expression, we need to bring the captures + into the lambda scope. */ + tree ns = decl_namespace_context (type); + push_nested_namespace (ns); + push_nested_class (type); + tree dummy_fco = maybe_add_dummy_lambda_op (r); + pop_nested_class (); + pop_nested_namespace (ns); + push_capture_proxies (r, /*early_p=*/true); + tree saved_ctp = current_template_parms; if (oldtmpl) { @@ -20493,6 +20616,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) --processing_template_decl; } + /* We are about to create the real operator(), so get rid of the old one. */ + if (dummy_fco) + remove_dummy_lambda_op (dummy_fco, r); + if (fntype == error_mark_node) r = error_mark_node; else @@ -20526,6 +20653,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) enclosing expression. */ cp_evaluated ev; + /* Now we're done with the parameter-declaration-clause, and should + assume "const" unless "mutable" was present. */ + LAMBDA_EXPR_CONST_QUAL_P (r) = LAMBDA_EXPR_CONST_QUAL_P (t); + bool nested = cfun; if (nested) push_function_context (); @@ -20594,6 +20725,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } out: + pop_bindings_and_leave_scope (); finish_struct (type, /*attr*/NULL_TREE); insert_pending_capture_proxies (); @@ -21211,7 +21343,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ++c_inhibit_evaluation_warnings; /* We only want to compute the number of arguments. */ if (PACK_EXPANSION_P (op)) - expanded = tsubst_pack_expansion (op, args, complain, in_decl); + { + expanded = NULL_TREE; + if (DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op))) + { + tree d = PACK_EXPANSION_PATTERN (op); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + if (TREE_CODE (d) == TREE_VEC) + { + tree b = TREE_VEC_ELT (d, 0); + if (!type_dependent_expression_p_push (b)) + { + expanded = void_node; + len = TREE_VEC_LENGTH (d) - 2; + } + } + } + } + if (!expanded) + expanded = tsubst_pack_expansion (op, args, complain, in_decl); + } else expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op), args, complain, in_decl); @@ -22169,6 +22322,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (DECL_NAME (t) == this_identifier && current_class_ptr) RETURN (current_class_ptr); + /* Parameters of non-templates map to themselves (e.g. in + expansion statement body). */ + if (DECL_CONTEXT (t) && !uses_template_parms (DECL_CONTEXT (t))) + RETURN (t); + /* This can happen for a parameter name used later in a function declaration (such as in a late-specified return type). Just make a dummy decl, since it's only used for its type. */ @@ -22385,12 +22543,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case OFFSET_REF: { - tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); + /* We should only get here for an OFFSET_REF like A::m; a .* in a + template is represented as a DOTSTAR_EXPR. */ + gcc_checking_assert + (same_type_p (TREE_TYPE (t), TREE_TYPE (TREE_OPERAND (t, 1)))); tree op0 = RECUR (TREE_OPERAND (t, 0)); tree op1 = RECUR (TREE_OPERAND (t, 1)); + tree type = TREE_TYPE (op1); r = build2 (OFFSET_REF, type, op0, op1); PTRMEM_OK_P (r) = PTRMEM_OK_P (t); - if (!mark_used (TREE_OPERAND (r, 1), complain) + if (!mark_used (op1, complain) && !(complain & tf_error)) RETURN (error_mark_node); RETURN (r); @@ -22503,6 +22665,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) type1 = tsubst_expr (type1, args, complain, in_decl); tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args, complain, in_decl); + if (TRAIT_EXPR_KIND (t) == CPTK_STRUCTURED_BINDING_SIZE + && type1 != error_mark_node + && !processing_template_decl) + /* __builtin_structured_binding_size handled separately + to make it SFINAE friendly. */ + RETURN (finish_structured_binding_size (TRAIT_EXPR_LOCATION (t), + type1, complain)); RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t), TRAIT_EXPR_KIND (t), type1, type2)); } @@ -29041,6 +29210,24 @@ value_dependent_expression_p (tree expression) case SIZEOF_EXPR: if (SIZEOF_EXPR_TYPE_P (expression)) return dependent_type_p (TREE_TYPE (TREE_OPERAND (expression, 0))); + if (tree p = TREE_OPERAND (expression, 0)) + if (PACK_EXPANSION_P (p) + && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (p))) + { + tree d = PACK_EXPANSION_PATTERN (p); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + /* [temp.dep.constexpr]/4: + Expressions of the following form are value-dependent: + sizeof ... ( identifier ) + unless the identifier is a structured binding pack whose + initializer is not dependent. */ + if (TREE_CODE (d) == TREE_VEC + && !type_dependent_expression_p (TREE_VEC_ELT (d, 0))) + return false; + } + } /* FALLTHRU */ case ALIGNOF_EXPR: case TYPEID_EXPR: @@ -29554,6 +29741,22 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, tree op = TREE_OPERAND (*tp, 0); if (code == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (*tp)) op = TREE_TYPE (op); + else if (code == SIZEOF_EXPR + && PACK_EXPANSION_P (op) + && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op))) + { + tree d = PACK_EXPANSION_PATTERN (op); + if (DECL_HAS_VALUE_EXPR_P (d)) + { + d = DECL_VALUE_EXPR (d); + if (TREE_CODE (d) == TREE_VEC + && !type_dependent_expression_p (TREE_VEC_ELT (d, 0))) + { + *walk_subtrees = 0; + return NULL_TREE; + } + } + } if (TYPE_P (op)) { if (dependent_type_p (op)) @@ -32448,6 +32651,401 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl, } } +struct expansion_stmt_bc +{ + tree break_label; + tree continue_label; + hash_set<tree> *pset; + location_t loc; + bool in_switch; +}; + +/* Helper function for finish_expansion_stmt. Find BREAK_STMT (not + nested inside of other WHILE_STMT, FOR_STMT, DO_STMT, TEMPLATE_FOR_STMT + or SWITCH_STMT) or CONTINUE_STMT (not nested inside those except + perhaps SWITCH_STMT) and replace them with GOTO_EXPR to lazily created + label. */ + +static tree +expansion_stmt_find_bc_r (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + expansion_stmt_bc *bc_data = (expansion_stmt_bc *) data; + switch (TREE_CODE (t)) + { + case WHILE_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (WHILE_STMT); ++i) + if (&TREE_OPERAND (t, i) != &WHILE_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case FOR_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (FOR_STMT); ++i) + if (&TREE_OPERAND (t, i) != &FOR_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case DO_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (DO_STMT); ++i) + if (&TREE_OPERAND (t, i) != &DO_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case TEMPLATE_FOR_STMT: + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (TEMPLATE_FOR_STMT); ++i) + if (&TREE_OPERAND (t, i) != &TEMPLATE_FOR_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + break; + case SWITCH_STMT: + if (!bc_data->in_switch) + { + *walk_subtrees = 0; + for (int i = 0; i < TREE_CODE_LENGTH (SWITCH_STMT); ++i) + if (&TREE_OPERAND (t, i) != &SWITCH_STMT_BODY (t)) + cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r, + data, bc_data->pset); + bc_data->in_switch = true; + cp_walk_tree (&SWITCH_STMT_BODY (t), expansion_stmt_find_bc_r, + data, bc_data->pset); + bc_data->in_switch = false; + } + break; + case BREAK_STMT: + if (!bc_data->in_switch) + { + if (!bc_data->break_label) + { + bc_data->break_label = create_artificial_label (bc_data->loc); + TREE_USED (bc_data->break_label) = 1; + LABEL_DECL_BREAK (bc_data->break_label) = true; + } + *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node, + bc_data->break_label); + } + break; + case CONTINUE_STMT: + if (!bc_data->continue_label) + { + bc_data->continue_label = create_artificial_label (bc_data->loc); + TREE_USED (bc_data->continue_label) = 1; + LABEL_DECL_CONTINUE (bc_data->continue_label) = true; + } + *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node, + bc_data->continue_label); + break; + default: + if (TYPE_P (t)) + *walk_subtrees = 0; + break; + } + return NULL_TREE; +} + +/* Finish an expansion-statement. */ + +void +finish_expansion_stmt (tree expansion_stmt, tree args, + tsubst_flags_t complain, tree in_decl) +{ + tree expansion_init = TEMPLATE_FOR_EXPR (expansion_stmt); + if (error_operand_p (expansion_init)) + return; + + enum expansion_stmt_kind { + esk_none, + esk_iterating, + esk_destructuring, + esk_enumerating + } kind = esk_none; + + unsigned HOST_WIDE_INT n = 0; + tree range_decl = TEMPLATE_FOR_DECL (expansion_stmt); + bool is_decomp = false; + if (TREE_CODE (range_decl) == TREE_VEC) + { + is_decomp = true; + range_decl = TREE_VEC_ELT (range_decl, 0); + } + if (error_operand_p (range_decl)) + return; + + location_t loc = DECL_SOURCE_LOCATION (range_decl); + tree begin = NULL_TREE; + auto_vec<tree, 8> destruct_decls; + if (BRACE_ENCLOSED_INITIALIZER_P (expansion_init)) + { + /* Enumerating expansion statements. */ + kind = esk_enumerating; + n = CONSTRUCTOR_NELTS (expansion_init); + } + else if (TYPE_REF_P (TREE_TYPE (expansion_init)) + ? TREE_CODE (TREE_TYPE (TREE_TYPE (expansion_init))) != ARRAY_TYPE + : TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE) + { + tree range_temp, begin_expr, end_expr, iter_type; + range_temp = convert_from_reference (build_range_temp (expansion_init)); + iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr, + &end_expr, tf_none); + if (begin_expr != error_mark_node && end_expr != error_mark_node) + { + kind = esk_iterating; + gcc_assert (iter_type); + } + } + if (kind == esk_iterating) + { + /* Iterating expansion statements. */ + tree end; + begin = cp_build_range_for_decls (loc, expansion_init, &end, true); + if (!error_operand_p (begin) && !error_operand_p (end)) + { + tree i = get_target_expr (begin); + tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, NULL_TREE); + tree r = get_target_expr (build_zero_cst (ptrdiff_type_node)); + tree iinc = build_x_unary_op (loc, PREINCREMENT_EXPR, + TARGET_EXPR_SLOT (i), NULL_TREE, + tf_warning_or_error); + tree rinc = build2 (PREINCREMENT_EXPR, ptrdiff_type_node, + TARGET_EXPR_SLOT (r), + build_int_cst (ptrdiff_type_node, 1)); + WHILE_BODY (w) = build_compound_expr (loc, iinc, rinc); + WHILE_COND (w) = build_x_binary_op (loc, NE_EXPR, i, ERROR_MARK, + end, ERROR_MARK, NULL_TREE, NULL, + tf_warning_or_error); + tree e = build_compound_expr (loc, r, i); + e = build_compound_expr (loc, e, w); + e = build_compound_expr (loc, e, TARGET_EXPR_SLOT (r)); + e = cxx_constant_value (e); + if (tree_fits_uhwi_p (e)) + n = tree_to_uhwi (e); + } + } + else if (kind == esk_none) + { + kind = esk_destructuring; + HOST_WIDE_INT sz = cp_decomp_size (loc, TREE_TYPE (expansion_init), + tf_warning_or_error); + if (sz < 0) + return; + n = sz; + tree auto_node = make_auto (); + tree decomp_type = cp_build_reference_type (auto_node, true); + decomp_type = do_auto_deduction (decomp_type, expansion_init, auto_node); + tree decl = build_decl (loc, VAR_DECL, NULL_TREE, decomp_type); + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_DECLARED_CONSTEXPR_P (decl) + = DECL_DECLARED_CONSTEXPR_P (range_decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (decl) = 1; + if (n) + fit_decomposition_lang_decl (decl, NULL_TREE); + pushdecl (decl); + cp_decomp this_decomp; + this_decomp.count = n; + destruct_decls.safe_grow (n, true); + for (unsigned HOST_WIDE_INT i = 0; i < n; ++i) + { + tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, make_auto ()); + TREE_USED (this_decl) = 1; + DECL_ARTIFICIAL (this_decl) = 1; + DECL_DECLARED_CONSTEXPR_P (this_decl) + = DECL_DECLARED_CONSTEXPR_P (decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (this_decl) = 1; + pushdecl (this_decl); + this_decomp.decl = this_decl; + destruct_decls[i] = this_decl; + } + DECL_NAME (decl) = for_range__identifier; + cp_finish_decl (decl, expansion_init, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING, n ? &this_decomp : NULL); + DECL_NAME (decl) = NULL_TREE; + } + + expansion_stmt_bc bc_data = { NULL_TREE, NULL_TREE, NULL, loc, false }; + + for (unsigned HOST_WIDE_INT i = 0; i < n; ++i) + { + tree scope = do_pushlevel (sk_block); + bool revert_outer + = (current_binding_level->level_chain + && current_binding_level->level_chain->kind == sk_template_for); + /* Don't diagnose redeclaration of for-range-declaration decls. + The sk_template_for block is reused for the originally parsed + source as well as the lowered one. In the original one + redeclaration of the for-range-declaration decls in the substatement + should be diagnosed (i.e. declarations of the same name in sk_block + of the body vs. declarations in sk_template_for block). In the + lowered case, the sk_block added by do_pushlevel (sk_block) above + will be block in the lowering of each Si. Those blocks do redeclare + for-range-declaration, so temporarily change sk_template_for + kind to sk_block to avoid it being diagnosed as invalid. */ + if (revert_outer) + current_binding_level->level_chain->kind = sk_block; + tree type = TREE_TYPE (range_decl); + if (args) + type = tsubst (type, args, complain | tf_tst_ok, in_decl); + tree decl = build_decl (loc, VAR_DECL, DECL_NAME (range_decl), type); + DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (range_decl); + if (args) + apply_late_template_attributes (&decl, DECL_ATTRIBUTES (decl), + /*flags=*/0, args, complain, + in_decl); + + DECL_DECLARED_CONSTEXPR_P (decl) + = DECL_DECLARED_CONSTEXPR_P (range_decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (decl) = 1; + pushdecl (decl); + tree init = NULL_TREE; + switch (kind) + { + case esk_enumerating: + init = CONSTRUCTOR_ELT (expansion_init, i)->value; + break; + case esk_iterating: + tree iter_init, auto_node, iter_type, iter; + iter_init + = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK, + build_int_cst (ptrdiff_type_node, i), + ERROR_MARK, NULL_TREE, NULL, + tf_warning_or_error); + auto_node = make_auto (); + iter_type = do_auto_deduction (auto_node, iter_init, auto_node); + iter = build_decl (loc, VAR_DECL, NULL_TREE, iter_type); + TREE_USED (iter) = 1; + DECL_ARTIFICIAL (iter) = 1; + TREE_STATIC (iter) = 1; + DECL_DECLARED_CONSTEXPR_P (iter) = 1; + pushdecl (iter); + cp_finish_decl (iter, iter_init, /*is_constant_init*/false, + NULL_TREE, LOOKUP_ONLYCONVERTING); + init = build_x_indirect_ref (loc, iter, RO_UNARY_STAR, NULL_TREE, + tf_warning_or_error); + break; + case esk_destructuring: + init = convert_from_reference (destruct_decls[i]); + break; + default: + gcc_unreachable (); + } + cp_decomp this_decomp = {}; + if (is_decomp) + { + fit_decomposition_lang_decl (decl, NULL_TREE); + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + this_decomp.count = TREE_VEC_LENGTH (v) - 1; + for (unsigned i = 0; i < this_decomp.count; ++i) + { + tree this_decl + = build_decl (loc, VAR_DECL, + DECL_NAME (TREE_VEC_ELT (v, i + 1)), + make_auto ()); + TREE_USED (this_decl) = 1; + DECL_ARTIFICIAL (this_decl) = 1; + DECL_ATTRIBUTES (this_decl) + = DECL_ATTRIBUTES (TREE_VEC_ELT (v, i + 1)); + if (DECL_PACK_P (TREE_VEC_ELT (v, i + 1))) + { + tree dtype = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (dtype) = this_decl; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1; + SET_TYPE_STRUCTURAL_EQUALITY (dtype); + tree type = cxx_make_type (TYPE_PACK_EXPANSION); + PACK_EXPANSION_PATTERN (type) = dtype; + SET_TYPE_STRUCTURAL_EQUALITY (type); + PACK_EXPANSION_PARAMETER_PACKS (type) = this_decl; + TREE_TYPE (this_decl) = type; + } + if (args) + apply_late_template_attributes (&this_decl, + DECL_ATTRIBUTES (this_decl), + /*flags=*/0, args, + complain, in_decl); + DECL_DECLARED_CONSTEXPR_P (this_decl) + = DECL_DECLARED_CONSTEXPR_P (decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + TREE_READONLY (this_decl) = 1; + pushdecl (this_decl); + this_decomp.decl = this_decl; + } + } + cp_finish_decl (decl, init, false, NULL_TREE, + LOOKUP_ONLYCONVERTING, is_decomp ? &this_decomp : NULL); + if (revert_outer) + current_binding_level->level_chain->kind = sk_template_for; + tree targs = args; + if (args == NULL_TREE) + { + targs = make_tree_vec (1); + TREE_VEC_ELT (targs, 0) = build_int_cst (ptrdiff_type_node, i + 1); + } + if (args != NULL_TREE + || push_tinst_level_loc (expansion_stmt, targs, loc)) + { + local_specialization_stack lss (lss_copy); + register_local_specialization (decl, range_decl); + if (is_decomp) + { + tree d = this_decomp.decl; + unsigned int cnt = this_decomp.count; + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + for (unsigned int i = 0; i < cnt; ++i, d = DECL_CHAIN (d)) + register_local_specialization (d, TREE_VEC_ELT (v, cnt - i)); + } + tsubst_stmt (TEMPLATE_FOR_BODY (expansion_stmt), + targs, complain, in_decl ? in_decl : range_decl); + if (args == NULL_TREE) + pop_tinst_level (); + } + tree stmt = do_poplevel (scope); + if (stmt) + { + add_stmt (stmt); + hash_set<tree> pset; + bc_data.continue_label = NULL_TREE; + bc_data.pset = &pset; + cp_walk_tree (&stmt, expansion_stmt_find_bc_r, &bc_data, &pset); + if (bc_data.continue_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, + bc_data.continue_label)); + } + } + if (bc_data.break_label) + add_stmt (build1 (LABEL_EXPR, void_type_node, bc_data.break_label)); + if (args == NULL_TREE) + { + TREE_TYPE (range_decl) = error_mark_node; + if (DECL_HAS_VALUE_EXPR_P (range_decl)) + { + SET_DECL_VALUE_EXPR (range_decl, NULL_TREE); + DECL_HAS_VALUE_EXPR_P (range_decl) = 0; + } + if (is_decomp) + { + tree v = TEMPLATE_FOR_DECL (expansion_stmt); + for (int i = 1; i < TREE_VEC_LENGTH (v); ++i) + { + tree d = TREE_VEC_ELT (v, i); + TREE_TYPE (d) = error_mark_node; + if (DECL_HAS_VALUE_EXPR_P (d)) + { + SET_DECL_VALUE_EXPR (d, NULL_TREE); + DECL_HAS_VALUE_EXPR_P (d) = 0; + } + } + } + } +} + /* Set up the hash tables for template instantiations. */ void |