From: Jakub Jelinek Date: Mon, 14 Nov 2016 05:02:58 +0000 (+0100) Subject: Implement P0217R3 - C++17 structured bindings X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=70f40fea6a317d7be82d1f02defb59381c7752e7;p=gcc.git Implement P0217R3 - C++17 structured bindings gcc/ * match.pd: Don't try to compare addresses of variables with DECL_VALUE_EXPR. gcc/cp/ * cp-tree.h (struct lang_decl_base): Add decomposition_p. (DECL_DECOMPOSITION_P): New (enum auto_deduction_context): Add adc_decomp_type. (enum cp_declarator_kind): Add cdk_decomp. * constexpr.c (cxx_eval_constant_expression): Look through DECL_VALUE_EXPR. (potential_constant_expression_1): Likewise. * decl.c (reshape_init): Preserve CONSTRUCTOR_IS_DIRECT_INIT. (check_initializer): Use build_aggr_init for DECL_DECOMPOSITION_P. (cp_finish_decl): Pass adc_decomp_type for decomposition. (find_decomp_class_base, get_tuple_size, get_tuple_element_type) (get_tuple_decomp_init, cp_finish_decomp): New. (grokdeclarator): Handle decomposition. * init.c (build_aggr_init): Handle decomposition array. (build_vec_init): Handle initialization from { array }. * name-lookup.c (add_function): Always wrap TEMPLATE_DECL in OVERLOAD. * parser.c (declarator_can_be_parameter_pack): Handle cdk_decomp. (function_declarator_p, strip_declarator_types) (cp_parser_check_declarator_template_parameters): Likewise. (cp_parser_range_for, cp_convert_range_for): Handle decomposition. (cp_parser_simple_declaration): Parse decomposition. (cp_parser_decomposition_declaration): New. * pt.c (tsubst_decomp_names): New. (subst_expr) [DECL_EXPR, RANGE_FOR_STMT]: Handle decomposition. (do_auto_deduction): Handle adc_decomp_type. * semantics.c (finish_decltype_type): Look through DECL_VALUE_EXPR. * typeck.c (is_bitfield_expr_with_lowered_type): Likewise. * tree.c (lvalue_kind): Likewise. (cp_build_reference_type): Handle reference collapsing. Co-Authored-By: Jason Merrill From-SVN: r242377 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ed44d9cecf7..323018240bd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2016-11-13 Jakub Jelinek + + * match.pd: Don't try to compare addresses of variables with + DECL_VALUE_EXPR. + 2016-11-13 Kugan Vivekanandarajah * ipa-cp.c (ipa_get_jf_pass_through_result): Skip unary expressions. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index daeb517452b..65574d3ee4b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +2016-11-13 Jakub Jelinek + Jason Merrill + + Implement P0217R3 - C++17 structured bindings + * cp-tree.h (struct lang_decl_base): Add decomposition_p. + (DECL_DECOMPOSITION_P): New + (enum auto_deduction_context): Add adc_decomp_type. + (enum cp_declarator_kind): Add cdk_decomp. + * constexpr.c (cxx_eval_constant_expression): Look through + DECL_VALUE_EXPR. + (potential_constant_expression_1): Likewise. + * decl.c (reshape_init): Preserve CONSTRUCTOR_IS_DIRECT_INIT. + (check_initializer): Use build_aggr_init for DECL_DECOMPOSITION_P. + (cp_finish_decl): Pass adc_decomp_type for decomposition. + (find_decomp_class_base, get_tuple_size, get_tuple_element_type) + (get_tuple_decomp_init, cp_finish_decomp): New. + (grokdeclarator): Handle decomposition. + * init.c (build_aggr_init): Handle decomposition array. + (build_vec_init): Handle initialization from { array }. + * name-lookup.c (add_function): Always wrap TEMPLATE_DECL in + OVERLOAD. + * parser.c (declarator_can_be_parameter_pack): Handle cdk_decomp. + (function_declarator_p, strip_declarator_types) + (cp_parser_check_declarator_template_parameters): Likewise. + (cp_parser_range_for, cp_convert_range_for): Handle decomposition. + (cp_parser_simple_declaration): Parse decomposition. + (cp_parser_decomposition_declaration): New. + * pt.c (tsubst_decomp_names): New. + (subst_expr) [DECL_EXPR, RANGE_FOR_STMT]: Handle decomposition. + (do_auto_deduction): Handle adc_decomp_type. + * semantics.c (finish_decltype_type): Look through DECL_VALUE_EXPR. + * typeck.c (is_bitfield_expr_with_lowered_type): Likewise. + * tree.c (lvalue_kind): Likewise. + (cp_build_reference_type): Handle reference collapsing. + 2016-11-13 Jason Merrill * call.c (build_new_method_call_1): Include template arguments in diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 739e902cf6a..e8c7702dede 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3770,7 +3770,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, return (*ctx->values->get (t)); case VAR_DECL: - if (is_capture_proxy (t)) + if (DECL_HAS_VALUE_EXPR_P (t)) return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t), lval, non_constant_p, overflow_p); /* fall through */ @@ -5037,6 +5037,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, return RECUR (TREE_OPERAND (t, 0), rval); case VAR_DECL: + if (DECL_HAS_VALUE_EXPR_P (t)) + return RECUR (DECL_VALUE_EXPR (t), rval); if (want_rval && !var_in_maybe_constexpr_fn (t) && !type_dependent_expression_p (t) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3e41a334350..8c2dbe1fba6 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2228,7 +2228,8 @@ struct GTY(()) lang_decl_base { unsigned u2sel : 1; unsigned concept_p : 1; /* applies to vars and functions */ unsigned var_declared_inline_p : 1; /* var */ - /* 2 spare bits */ + unsigned decomposition_p : 1; /* var */ + /* 1 spare bit */ }; /* True for DECL codes which have template info and access. */ @@ -3626,6 +3627,16 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \ = true) +/* Nonzero if NODE is the artificial VAR_DECL for decomposition + declaration. */ +#define DECL_DECOMPOSITION_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ + ? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p \ + : false) +#define SET_DECL_DECOMPOSITION_P(NODE) \ + (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.decomposition_p \ + = true) + /* Nonzero if NODE is an inline VAR_DECL. In C++17, static data members declared with constexpr specifier are implicitly inline variables. */ #define DECL_INLINE_VAR_P(NODE) \ @@ -5165,7 +5176,8 @@ enum auto_deduction_context adc_variable_type, /* Variable initializer deduction */ adc_return_type, /* Return type deduction */ adc_unify, /* Template argument deduction */ - adc_requirement /* Argument dedution constraint */ + adc_requirement, /* Argument deduction constraint */ + adc_decomp_type /* Decomposition declaration initializer deduction */ }; /* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */ @@ -5382,6 +5394,7 @@ enum cp_declarator_kind { cdk_pointer, cdk_reference, cdk_ptrmem, + cdk_decomp, cdk_error }; @@ -5412,7 +5425,8 @@ struct cp_declarator { /* Whether we parsed an ellipsis (`...') just before the declarator, to indicate this is a parameter pack. */ BOOL_BITFIELD parameter_pack_p : 1; - location_t id_loc; /* Currently only set for cdk_id and cdk_function. */ + location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and + cdk_function. */ /* GNU Attributes that apply to this declarator. If the declarator is a pointer or a reference, these attribute apply to the type pointed to. */ @@ -5421,8 +5435,8 @@ struct cp_declarator { declarator is a pointer or a reference, these attributes apply to the pointer, rather than to the type pointed to. */ tree std_attributes; - /* For all but cdk_id and cdk_error, the contained declarator. For - cdk_id and cdk_error, guaranteed to be NULL. */ + /* For all but cdk_id, cdk_decomp and cdk_error, the contained declarator. + For cdk_id, cdk_decomp and cdk_error, guaranteed to be NULL. */ cp_declarator *declarator; union { /* For identifiers. */ @@ -5794,6 +5808,7 @@ extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, extern void start_decl_1 (tree, bool); extern bool check_array_initializer (tree, tree, tree); extern void cp_finish_decl (tree, tree, bool, tree, int); +extern void cp_finish_decomp (tree, tree, unsigned int); extern int cp_complete_array_type (tree *, tree, bool); extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t); extern tree build_ptrmemfunc_type (tree); @@ -6066,7 +6081,7 @@ extern tree implicitly_declare_fn (special_function_kind, tree, extern bool maybe_clone_body (tree); /* In parser.c */ -extern tree cp_convert_range_for (tree, tree, tree, bool); +extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool); extern bool parsing_nsdmi (void); extern void inject_this_parameter (tree, cp_cv_quals); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ccd65b104a2..f142c1fb931 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6074,6 +6074,10 @@ reshape_init (tree type, tree init, tsubst_flags_t complain) return error_mark_node; } + if (CONSTRUCTOR_IS_DIRECT_INIT (init) + && BRACE_ENCLOSED_INITIALIZER_P (new_init)) + CONSTRUCTOR_IS_DIRECT_INIT (new_init) = true; + return new_init; } @@ -6254,7 +6258,8 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) if (type == error_mark_node) return NULL_TREE; - if ((type_build_ctor_call (type) || CLASS_TYPE_P (type)) + if ((type_build_ctor_call (type) || CLASS_TYPE_P (type) + || (DECL_DECOMPOSITION_P (decl) && TREE_CODE (type) == ARRAY_TYPE)) && !(flags & LOOKUP_ALREADY_DIGESTED) && !(init && BRACE_ENCLOSED_INITIALIZER_P (init) && CP_AGGREGATE_TYPE_P (type) @@ -6770,10 +6775,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, d_init = build_x_compound_expr_from_list (d_init, ELK_INIT, tf_warning_or_error); d_init = resolve_nondeduced_context (d_init, tf_warning_or_error); - type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, - auto_node, - tf_warning_or_error, - adc_variable_type); + enum auto_deduction_context adc = adc_variable_type; + if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) + adc = adc_decomp_type; + type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node, + tf_warning_or_error, adc); if (type == error_mark_node) return; if (TREE_CODE (type) == FUNCTION_TYPE) @@ -7137,6 +7143,390 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); } +/* For class TYPE return itself or some its bases that contain + any direct non-static data members. Return error_mark_node if an + error has been diagnosed. */ + +static tree +find_decomp_class_base (location_t loc, tree type, tree ret) +{ + bool member_seen = false; + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) + continue; + else if (ret) + return type; + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) + error_at (loc, "cannot decompose class type %qT because it has an " + "anonymous struct member", type); + else + error_at (loc, "cannot decompose class type %qT because it has an " + "anonymous union member", type); + inform (DECL_SOURCE_LOCATION (field), "declared here"); + return error_mark_node; + } + else if (TREE_PRIVATE (field) || TREE_PROTECTED (field)) + { + error_at (loc, "cannot decompose non-public member %qD of %qT", + field, type); + inform (DECL_SOURCE_LOCATION (field), + TREE_PRIVATE (field) ? "declared private here" + : "declared protected here"); + return error_mark_node; + } + else + member_seen = true; + + tree base_binfo, binfo; + tree orig_ret = ret; + int i; + if (member_seen) + ret = type; + for (binfo = TYPE_BINFO (type), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret); + if (t == error_mark_node) + return error_mark_node; + if (t != NULL_TREE) + { + 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); + return error_mark_node; + } + else if (orig_ret != NULL_TREE) + return t; + else if (ret == t) + /* OK, found the same base along another path. We'll complain + in convert_to_base if it's ambiguous. */; + 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); + return error_mark_node; + } + else + ret = t; + } + } + return ret; +} + +/* Return std::tuple_size::value. */ + +tree +get_tuple_size (tree type) +{ + tree args = make_tree_vec (1); + TREE_VEC_ELT (args, 0) = type; + tree inst = lookup_template_class (get_identifier ("tuple_size"), args, + /*in_decl*/NULL_TREE, + /*context*/std_node, + /*entering_scope*/false, tf_none); + tree val = lookup_qualified_name (inst, get_identifier ("value"), + /*type*/false, /*complain*/false); + if (TREE_CODE (val) == VAR_DECL || TREE_CODE (val) == CONST_DECL) + val = maybe_constant_value (val); + if (TREE_CODE (val) == INTEGER_CST) + return val; + else + return NULL_TREE; +} + +/* Return std::tuple_element::type. */ + +tree +get_tuple_element_type (tree type, unsigned i) +{ + tree args = make_tree_vec (2); + TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i); + TREE_VEC_ELT (args, 1) = type; + tree inst = lookup_template_class (get_identifier ("tuple_element"), args, + /*in_decl*/NULL_TREE, + /*context*/std_node, + /*entering_scope*/false, + tf_warning_or_error); + return make_typename_type (inst, get_identifier ("type"), + none_type, tf_warning_or_error); +} + +/* Return e.get() or get(e). */ + +tree +get_tuple_decomp_init (tree decl, unsigned i) +{ + tree get_id = get_identifier ("get"); + tree targs = make_tree_vec (1); + TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i); + + tree etype = TREE_TYPE (decl); + tree e = convert_from_reference (decl); + + /* [The id-expression] e is an lvalue if the type of the entity e is an + lvalue reference and an xvalue otherwise. */ + if (TREE_CODE (etype) != REFERENCE_TYPE + || TYPE_REF_IS_RVALUE (etype)) + e = move (e); + + tree fns = lookup_qualified_name (TREE_TYPE (e), get_id, + /*type*/false, /*complain*/false); + if (fns != error_mark_node) + { + fns = lookup_template_function (fns, targs); + return build_new_method_call (e, fns, /*args*/NULL, + /*path*/NULL_TREE, LOOKUP_NORMAL, + /*fn_p*/NULL, tf_warning_or_error); + } + else + { + vec *args = make_tree_vector_single (e); + fns = lookup_template_function (get_id, targs); + fns = perform_koenig_lookup (fns, args, tf_warning_or_error); + return finish_call_expr (fns, &args, /*novirt*/false, + /*koenig*/true, tf_warning_or_error); + } +} + +/* 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 + those decls. */ + +void +cp_finish_decomp (tree decl, tree first, unsigned int count) +{ + location_t loc = DECL_SOURCE_LOCATION (decl); + if (error_operand_p (decl)) + { + error_out: + while (count--) + { + TREE_TYPE (first) = error_mark_node; + if (DECL_HAS_VALUE_EXPR_P (first)) + { + SET_DECL_VALUE_EXPR (first, NULL_TREE); + DECL_HAS_VALUE_EXPR_P (first) = 0; + } + first = DECL_CHAIN (first); + } + return; + } + + if (type_dependent_expression_p (decl) + /* This happens for range for when not in templates. + Still add the DECL_VALUE_EXPRs for later processing. */ + || (!processing_template_decl + && type_uses_auto (TREE_TYPE (decl)))) + { + for (unsigned int i = 0; i < count; i++) + { + if (!DECL_HAS_VALUE_EXPR_P (first)) + { + tree v = build_nt (ARRAY_REF, decl, + size_int (count - i - 1), + NULL_TREE, NULL_TREE); + SET_DECL_VALUE_EXPR (first, v); + DECL_HAS_VALUE_EXPR_P (first) = 1; + } + if (processing_template_decl) + { + retrofit_lang_decl (first); + SET_DECL_DECOMPOSITION_P (first); + } + first = DECL_CHAIN (first); + } + return; + } + + auto_vec v; + v.safe_grow (count); + tree d = first; + for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) + { + v[count - i - 1] = d; + if (processing_template_decl) + { + retrofit_lang_decl (d); + SET_DECL_DECOMPOSITION_P (d); + } + } + + tree type = TREE_TYPE (decl); + tree eltype = NULL_TREE; + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + unsigned HOST_WIDE_INT eltscnt = 0; + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree nelts; + nelts = array_type_nelts_top (type); + if (nelts == error_mark_node) + goto error_out; + if (!tree_fits_uhwi_p (nelts)) + { + error_at (loc, "cannot decompose variable length array %qT", type); + goto error_out; + } + eltscnt = tree_to_uhwi (nelts); + if (count != eltscnt) + { + cnt_mismatch: + if (count > eltscnt) + error_at (loc, "%u names provided while %qT decomposes into " + "%wu elements", count, type, eltscnt); + else + error_at (loc, "only %u names provided while %qT decomposes into " + "%wu elements", count, type, eltscnt); + goto error_out; + } + eltype = TREE_TYPE (type); + for (unsigned int i = 0; i < count; i++) + { + TREE_TYPE (v[i]) = eltype; + layout_decl (v[i], 0); + tree t = convert_from_reference (decl); + t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF, + eltype, t, size_int (i), NULL_TREE, + NULL_TREE); + SET_DECL_VALUE_EXPR (v[i], t); + DECL_HAS_VALUE_EXPR_P (v[i]) = 1; + } + } + /* 2 GNU extensions. */ + else if (TREE_CODE (type) == COMPLEX_TYPE) + { + eltscnt = 2; + if (count != eltscnt) + goto cnt_mismatch; + eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); + for (unsigned int i = 0; i < count; i++) + { + TREE_TYPE (v[i]) = eltype; + layout_decl (v[i], 0); + tree t = convert_from_reference (decl); + t = build1_loc (DECL_SOURCE_LOCATION (v[i]), + i ? IMAGPART_EXPR : REALPART_EXPR, eltype, + t); + SET_DECL_VALUE_EXPR (v[i], t); + DECL_HAS_VALUE_EXPR_P (v[i]) = 1; + } + } + else if (TREE_CODE (type) == VECTOR_TYPE) + { + eltscnt = TYPE_VECTOR_SUBPARTS (type); + if (count != eltscnt) + goto cnt_mismatch; + eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); + for (unsigned int i = 0; i < count; i++) + { + TREE_TYPE (v[i]) = eltype; + layout_decl (v[i], 0); + tree t = convert_from_reference (decl); + convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]), + &t, size_int (i)); + t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF, + eltype, t, size_int (i), NULL_TREE, + NULL_TREE); + SET_DECL_VALUE_EXPR (v[i], t); + DECL_HAS_VALUE_EXPR_P (v[i]) = 1; + } + } + else if (tree tsize = get_tuple_size (type)) + { + eltscnt = tree_to_uhwi (tsize); + if (count != eltscnt) + goto cnt_mismatch; + for (unsigned i = 0; i < count; ++i) + { + location_t sloc = input_location; + location_t dloc = DECL_SOURCE_LOCATION (v[i]); + + input_location = dloc; + tree init = get_tuple_decomp_init (decl, i); + tree eltype = (init == error_mark_node ? error_mark_node + : get_tuple_element_type (type, i)); + input_location = sloc; + + if (init == error_mark_node || eltype == error_mark_node) + { + inform (dloc, "in initialization of decomposition variable %qD", + v[i]); + goto error_out; + } + eltype = cp_build_reference_type (eltype, !lvalue_p (init)); + TREE_TYPE (v[i]) = eltype; + layout_decl (v[i], 0); + if (DECL_HAS_VALUE_EXPR_P (v[i])) + { + /* In this case the names are variables, not just proxies. */ + SET_DECL_VALUE_EXPR (v[i], NULL_TREE); + DECL_HAS_VALUE_EXPR_P (v[i]) = 0; + } + cp_finish_decl (v[i], init, /*constexpr*/false, + /*asm*/NULL_TREE, LOOKUP_NORMAL); + } + } + else if (TREE_CODE (type) == UNION_TYPE) + { + error_at (loc, "cannot decompose union type %qT", type); + goto error_out; + } + else if (!CLASS_TYPE_P (type)) + { + error_at (loc, "cannot decompose non-array non-class type %qT", type); + goto error_out; + } + else + { + tree btype = find_decomp_class_base (loc, type, NULL_TREE); + if (btype == error_mark_node) + goto error_out; + else if (btype == NULL_TREE) + { + error_at (loc, "cannot decompose class type %qT without non-static " + "data members", type); + goto error_out; + } + for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) + continue; + else + eltscnt++; + if (count != eltscnt) + goto cnt_mismatch; + tree t = convert_from_reference (decl); + if (type != btype) + { + t = convert_to_base (t, btype, /*check_access*/true, + /*nonnull*/false, tf_warning_or_error); + type = btype; + } + unsigned int i = 0; + for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) + continue; + else + { + tree tt = finish_non_static_data_member (field, t, NULL_TREE); + tree probe = tt; + if (REFERENCE_REF_P (probe)) + probe = TREE_OPERAND (probe, 0); + TREE_TYPE (v[i]) = TREE_TYPE (probe); + layout_decl (v[i], 0); + SET_DECL_VALUE_EXPR (v[i], tt); + DECL_HAS_VALUE_EXPR_P (v[i]) = 1; + i++; + } + } +} + /* Returns a declaration for a VAR_DECL as if: extern "C" TYPE NAME; @@ -9449,7 +9839,7 @@ grokdeclarator (const cp_declarator *declarator, cp_storage_class storage_class; bool unsigned_p, signed_p, short_p, long_p, thread_p; bool type_was_error_mark_node = false; - bool parameter_pack_p = declarator? declarator->parameter_pack_p : false; + bool parameter_pack_p = declarator ? declarator->parameter_pack_p : false; bool template_type_arg = false; bool template_parm_flag = false; bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef); @@ -9650,6 +10040,10 @@ grokdeclarator (const cp_declarator *declarator, case cdk_ptrmem: break; + case cdk_decomp: + name = "decomposition"; + break; + case cdk_error: return error_mark_node; @@ -9859,15 +10253,15 @@ grokdeclarator (const cp_declarator *declarator, if (explicit_intN) { if (! int_n_enabled_p[declspecs->int_n_idx]) - { - error ("%<__int%d%> is not supported by this target", - int_n_data[declspecs->int_n_idx].bitsize); - explicit_intN = false; - } + { + error ("%<__int%d%> is not supported by this target", + int_n_data[declspecs->int_n_idx].bitsize); + explicit_intN = false; + } else if (pedantic && ! in_system_header_at (input_location)) - pedwarn (input_location, OPT_Wpedantic, - "ISO C++ does not support %<__int%d%> for %qs", - int_n_data[declspecs->int_n_idx].bitsize, name); + pedwarn (input_location, OPT_Wpedantic, + "ISO C++ does not support %<__int%d%> for %qs", + int_n_data[declspecs->int_n_idx].bitsize, name); } /* Now process the modifiers that were specified @@ -10093,6 +10487,79 @@ grokdeclarator (const cp_declarator *declarator, virtualp = 0; } + if (innermost_code == cdk_decomp) + { + location_t loc = (declarator->kind == cdk_reference + ? declarator->declarator->id_loc : declarator->id_loc); + if (inlinep) + error_at (declspecs->locations[ds_inline], + "decomposition declaration cannot be declared %"); + if (typedef_p) + error_at (declspecs->locations[ds_typedef], + "decomposition declaration cannot be declared %"); + if (constexpr_p) + error_at (declspecs->locations[ds_constexpr], "decomposition " + "declaration cannot be declared %"); + if (thread_p) + error_at (declspecs->locations[ds_thread], + "decomposition declaration cannot be declared %qs", + declspecs->gnu_thread_keyword_p + ? "__thread" : "thread_local"); + if (concept_p) + error_at (declspecs->locations[ds_concept], + "decomposition declaration cannot be declared %"); + switch (storage_class) + { + case sc_none: + break; + case sc_register: + error_at (loc, "decomposition declaration cannot be declared " + "%"); + break; + case sc_static: + error_at (loc, "decomposition declaration cannot be declared " + "%"); + break; + case sc_extern: + error_at (loc, "decomposition declaration cannot be declared " + "%"); + break; + case sc_mutable: + error_at (loc, "decomposition declaration cannot be declared " + "%"); + break; + case sc_auto: + error_at (loc, "decomposition declaration cannot be declared " + "C++98 %"); + break; + default: + gcc_unreachable (); + } + if (TREE_CODE (type) != TEMPLATE_TYPE_PARM + || TYPE_IDENTIFIER (type) != get_identifier ("auto")) + { + if (type != error_mark_node) + { + error_at (loc, "decomposition declaration cannot be declared " + "with type %qT", type); + inform (loc, + "type must be cv-qualified % or reference to " + "cv-qualified %"); + } + type = build_qualified_type (make_auto (), type_quals); + declspecs->type = type; + } + inlinep = 0; + typedef_p = 0; + constexpr_p = 0; + thread_p = 0; + concept_p = 0; + storage_class = sc_none; + staticp = 0; + declspecs->storage_class = sc_none; + declspecs->locations[ds_thread] = UNKNOWN_LOCATION; + } + /* Static anonymous unions are dealt with here. */ if (staticp && decl_context == TYPENAME && declspecs->type @@ -10232,7 +10699,7 @@ grokdeclarator (const cp_declarator *declarator, attr_flags); } - if (declarator->kind == cdk_id) + if (declarator->kind == cdk_id || declarator->kind == cdk_decomp) break; inner_declarator = declarator->declarator; @@ -10743,6 +11210,7 @@ grokdeclarator (const cp_declarator *declarator, is non-NULL, we know it is a cdk_id declarator; otherwise, we would not have exited the loop above. */ if (declarator + && declarator->kind == cdk_id && declarator->u.id.qualifying_scope && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope)) { @@ -10754,13 +11222,14 @@ grokdeclarator (const cp_declarator *declarator, { if (friendp) { - permerror (input_location, "member functions are implicitly friends of their class"); + permerror (input_location, "member functions are implicitly " + "friends of their class"); friendp = 0; } else permerror (declarator->id_loc, - "extra qualification %<%T::%> on member %qs", - ctype, name); + "extra qualification %<%T::%> on member %qs", + ctype, name); } else if (/* If the qualifying type is already complete, then we can skip the following checks. */ @@ -11133,7 +11602,8 @@ grokdeclarator (const cp_declarator *declarator, else if (unqualified_id == NULL_TREE && decl_context != PARM && decl_context != CATCHPARM && TREE_CODE (type) != UNION_TYPE - && ! bitfield) + && ! bitfield + && innermost_code != cdk_decomp) { error ("abstract declarator %qT used as declaration", type); return error_mark_node; @@ -11719,6 +12189,14 @@ grokdeclarator (const cp_declarator *declarator, if (inlinep) mark_inline_variable (decl); + if (innermost_code == cdk_decomp) + { + gcc_assert (declarator && declarator->kind == cdk_decomp); + DECL_SOURCE_LOCATION (decl) = declarator->id_loc; + retrofit_lang_decl (decl); + DECL_ARTIFICIAL (decl) = 1; + SET_DECL_DECOMPOSITION_P (decl); + } } if (VAR_P (decl) && !initialized) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5eba4c3e18c..1fad79cb247 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1575,27 +1575,34 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) if (TREE_CODE (type) == ARRAY_TYPE) { - tree itype; + tree itype = init ? TREE_TYPE (init) : NULL_TREE; + int from_array = 0; - /* An array may not be initialized use the parenthesized - initialization form -- unless the initializer is "()". */ - if (init && TREE_CODE (init) == TREE_LIST) + if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp)) + from_array = 1; + else { - if (complain & tf_error) - error ("bad array initializer"); - return error_mark_node; + /* An array may not be initialized use the parenthesized + initialization form -- unless the initializer is "()". */ + if (init && TREE_CODE (init) == TREE_LIST) + { + if (complain & tf_error) + error ("bad array initializer"); + return error_mark_node; + } + /* Must arrange to initialize each element of EXP + from elements of INIT. */ + if (cv_qualified_p (type)) + TREE_TYPE (exp) = cv_unqualified (type); + if (itype && cv_qualified_p (itype)) + TREE_TYPE (init) = cv_unqualified (itype); + from_array = (itype && same_type_p (TREE_TYPE (init), + TREE_TYPE (exp))); } - /* Must arrange to initialize each element of EXP - from elements of INIT. */ - itype = init ? TREE_TYPE (init) : NULL_TREE; - if (cv_qualified_p (type)) - TREE_TYPE (exp) = cv_unqualified (type); - if (itype && cv_qualified_p (itype)) - TREE_TYPE (init) = cv_unqualified (itype); + stmt_expr = build_vec_init (exp, NULL_TREE, init, /*explicit_value_init_p=*/false, - itype && same_type_p (TREE_TYPE (init), - TREE_TYPE (exp)), + from_array, complain); TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; @@ -3891,6 +3898,18 @@ build_vec_init (tree base, tree maxindex, tree init, base = get_temp_regvar (ptype, rval); iterator = get_temp_regvar (ptrdiff_type_node, maxindex); + bool direct_init = false; + if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init) + && CONSTRUCTOR_NELTS (init) == 1) + { + tree elt = CONSTRUCTOR_ELT (init, 0)->value; + if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE) + { + direct_init = DIRECT_LIST_INIT_P (init); + init = elt; + } + } + /* If initializing one array from another, initialize element by element. We rely upon the below calls to do the argument checking. Evaluate the initializer before entering the try block. */ @@ -4115,6 +4134,8 @@ build_vec_init (tree base, tree maxindex, tree init, from = build1 (INDIRECT_REF, itype, base2); if (xvalue) from = move (from); + if (direct_init) + from = build_tree_list (NULL_TREE, from); } else from = NULL_TREE; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 172ec820b4d..7ad65b89599 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5393,7 +5393,7 @@ add_function (struct arg_lookup *k, tree fn) function templates are ignored. */; else if (k->fn_set && k->fn_set->add (fn)) /* It's already in the list. */; - else if (!k->functions) + else if (!k->functions && TREE_CODE (fn) != TEMPLATE_DECL) k->functions = fn; else if (fn == k->functions) ; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e669c0d1c8a..9360ab0cbd6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1668,6 +1668,7 @@ declarator_can_be_parameter_pack (cp_declarator *declarator) { case cdk_id: case cdk_array: + case cdk_decomp: found = true; break; @@ -1721,6 +1722,7 @@ function_declarator_p (const cp_declarator *declarator) && declarator->declarator->kind == cdk_id) return true; if (declarator->kind == cdk_id + || declarator->kind == cdk_decomp || declarator->kind == cdk_error) return false; declarator = declarator->declarator; @@ -2200,6 +2202,8 @@ static void cp_parser_static_assert (cp_parser *, bool); static tree cp_parser_decltype (cp_parser *); +static tree cp_parser_decomposition_declaration + (cp_parser *, cp_decl_specifier_seq *, tree *, location_t *); /* Declarators [gram.dcl.decl] */ @@ -11471,16 +11475,45 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, bool ivdep) { tree stmt, range_expr; - cxx_binding *binding = NULL; - tree name = NULL_TREE; + auto_vec bindings; + auto_vec names; + tree decomp_first_name = NULL_TREE; + unsigned int decomp_cnt = 0; /* 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) { - name = DECL_NAME (range_decl); - binding = IDENTIFIER_BINDING (name); - IDENTIFIER_BINDING (name) = binding->previous; + 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 + && VAR_P (TREE_OPERAND (v, 0)) + && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0))) + { + tree d = range_decl; + range_decl = TREE_OPERAND (v, 0); + decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1; + decomp_first_name = d; + for (unsigned int i = 0; i < decomp_cnt; i++, d = DECL_CHAIN (d)) + { + 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.quick_push (name); + bindings.quick_push (IDENTIFIER_BINDING (name)); + IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous; + } } if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) @@ -11491,11 +11524,12 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, else range_expr = cp_parser_expression (parser); - /* Put the range declaration back into scope. */ - if (range_decl != error_mark_node) + /* Put the range declaration(s) back into scope. */ + for (unsigned int i = 0; i < names.length (); i++) { - binding->previous = IDENTIFIER_BINDING (name); - IDENTIFIER_BINDING (name) = binding; + cxx_binding *binding = bindings[i]; + binding->previous = IDENTIFIER_BINDING (names[i]); + IDENTIFIER_BINDING (names[i]) = binding; } /* If in template, STMT is converted to a normal for-statement @@ -11516,7 +11550,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, else { stmt = begin_for_stmt (scope, init); - stmt = cp_convert_range_for (stmt, range_decl, range_expr, ivdep); + stmt = cp_convert_range_for (stmt, range_decl, range_expr, + decomp_first_name, decomp_cnt, ivdep); } return stmt; } @@ -11608,6 +11643,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr) tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, + tree decomp_first_name, unsigned int decomp_cnt, bool ivdep) { tree begin, end; @@ -11681,6 +11717,8 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, tf_warning_or_error), /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); + if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) + cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt); return statement; } @@ -12554,6 +12592,8 @@ cp_parser_block_declaration (cp_parser *parser, simple-declaration: decl-specifier-seq [opt] init-declarator-list [opt] ; + decl-specifier-seq ref-qualifier [opt] [ identifier-list ] + brace-or-equal-initializer ; init-declarator-list: init-declarator @@ -12639,6 +12679,45 @@ cp_parser_simple_declaration (cp_parser* parser, && !cp_parser_error_occurred (parser)) cp_parser_commit_to_tentative_parse (parser); + /* Look for C++17 decomposition declaration. */ + for (size_t n = 1; ; n++) + if (cp_lexer_nth_token_is (parser->lexer, n, CPP_AND) + || cp_lexer_nth_token_is (parser->lexer, n, CPP_AND_AND)) + continue; + else if (cp_lexer_nth_token_is (parser->lexer, n, CPP_OPEN_SQUARE) + && !cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_SQUARE) + && decl_specifiers.any_specifiers_p) + { + tree decl + = cp_parser_decomposition_declaration (parser, &decl_specifiers, + maybe_range_for_decl, + &init_loc); + + /* The next token should be either a `,' or a `;'. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + /* If it's a `;', we are done. */ + if (token->type == CPP_SEMICOLON || maybe_range_for_decl) + goto finish; + /* Anything else is an error. */ + else + { + /* If we have already issued an error message we don't need + to issue another one. */ + if ((decl != error_mark_node + && DECL_INITIAL (decl) != error_mark_node) + || cp_parser_uncommitted_to_tentative_parse_p (parser)) + cp_parser_error (parser, "expected %<,%> or %<;%>"); + /* Skip tokens until we reach the end of the statement. */ + cp_parser_skip_to_end_of_statement (parser); + /* If the next token is now a `;', consume it. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + goto done; + } + } + else + break; + tree last_type; last_type = NULL_TREE; @@ -12791,6 +12870,7 @@ cp_parser_simple_declaration (cp_parser* parser, } /* Consume the `;'. */ + finish: if (!maybe_range_for_decl) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); else if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) @@ -12806,6 +12886,143 @@ cp_parser_simple_declaration (cp_parser* parser, pop_deferring_access_checks (); } +/* Helper of cp_parser_simple_declaration, parse a decomposition declaration. + decl-specifier-seq ref-qualifier [opt] [ identifier-list ] + brace-or-equal-initializer ; */ + +static tree +cp_parser_decomposition_declaration (cp_parser *parser, + cp_decl_specifier_seq *decl_specifiers, + tree *maybe_range_for_decl, + location_t *init_loc) +{ + cp_ref_qualifier ref_qual = cp_parser_ref_qualifier_opt (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. */ + auto_vec v; + if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + while (true) + { + cp_expr e = cp_parser_identifier (parser); + if (e.get_value () == error_mark_node) + break; + v.safe_push (e); + if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + + location_t end_loc = cp_lexer_peek_token (parser->lexer)->location; + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) + { + end_loc = UNKNOWN_LOCATION; + cp_parser_skip_to_closing_parenthesis_1 (parser, true, CPP_CLOSE_SQUARE, + false); + if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + cp_lexer_consume_token (parser->lexer); + else + { + cp_parser_skip_to_end_of_statement (parser); + return error_mark_node; + } + } + + if (cxx_dialect < cxx1z) + pedwarn (loc, 0, "decomposition declaration only available with " + "-std=c++1z or -std=gnu++1z"); + + tree pushed_scope; + cp_declarator *declarator = make_declarator (cdk_decomp); + loc = end_loc == UNKNOWN_LOCATION ? loc : make_location (loc, loc, end_loc); + declarator->id_loc = loc; + if (ref_qual != REF_QUAL_NONE) + declarator = make_reference_declarator (TYPE_UNQUALIFIED, declarator, + ref_qual == REF_QUAL_RVALUE, + NULL_TREE); + tree decl = start_decl (declarator, decl_specifiers, SD_INITIALIZED, + NULL_TREE, decl_specifiers->attributes, + &pushed_scope); + + unsigned int i; + cp_expr e; + cp_decl_specifier_seq decl_specs; + clear_decl_specs (&decl_specs); + decl_specs.type = make_auto (); + tree prev = decl; + FOR_EACH_VEC_ELT (v, i, e) + { + if (i == 0) + declarator = make_id_declarator (NULL_TREE, e.get_value (), sfk_none); + else + declarator->u.id.unqualified_name = e.get_value (); + declarator->id_loc = e.get_location (); + tree elt_pushed_scope; + tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED, + NULL_TREE, NULL_TREE, &elt_pushed_scope); + if (decl2 == error_mark_node) + decl = error_mark_node; + else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev) + { + /* Ensure we've diagnosed redeclaration if we aren't creating + a new VAR_DECL. */ + gcc_assert (errorcount); + decl = error_mark_node; + } + else + prev = decl2; + if (elt_pushed_scope) + pop_scope (elt_pushed_scope); + } + + if (v.is_empty ()) + { + error_at (loc, "empty decomposition declaration"); + decl = error_mark_node; + } + + if (maybe_range_for_decl == NULL + || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) + { + bool non_constant_p = false, is_direct_init = false; + tree initializer; + *init_loc = cp_lexer_peek_token (parser->lexer)->location; + /* Parse the initializer. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + initializer = cp_parser_braced_list (parser, &non_constant_p); + CONSTRUCTOR_IS_DIRECT_INIT (initializer) = 1; + is_direct_init = true; + } + else + { + /* Consume the `='. */ + cp_parser_require (parser, CPP_EQ, RT_EQ); + initializer = cp_parser_initializer_clause (parser, &non_constant_p); + } + + if (decl != error_mark_node) + { + cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE, + is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT); + cp_finish_decomp (decl, prev, v.length ()); + } + } + else if (decl != error_mark_node) + { + *maybe_range_for_decl = prev; + /* Ensure DECL_VALUE_EXPR is created for all the decls but + the underlying DECL. */ + cp_finish_decomp (decl, prev, v.length ()); + } + + if (pushed_scope) + pop_scope (pushed_scope); + + return decl; +} + /* Parse a decl-specifier-seq. decl-specifier-seq: @@ -18628,6 +18845,7 @@ strip_declarator_types (tree type, cp_declarator *declarator) switch (d->kind) { case cdk_id: + case cdk_decomp: case cdk_error: d = NULL; break; @@ -25502,6 +25720,7 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser, return (cp_parser_check_declarator_template_parameters (parser, declarator->declarator, declarator_location)); + case cdk_decomp: case cdk_error: return true; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d9499d9284a..7eeb27ddd1c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15311,6 +15311,55 @@ tsubst_find_omp_teams (tree *tp, int *walk_subtrees, void *) return NULL_TREE; } +/* Helper function for tsubst_expr. For decomposition declaration + artificial base DECL, which is tsubsted PATTERN_DECL, tsubst + also the corresponding decls representing the identifiers + of the decomposition declaration. Return DECL if successful + or error_mark_node otherwise, set *FIRST to the first decl + in the list chained through DECL_CHAIN and *CNT to the number + of such decls. */ + +static tree +tsubst_decomp_names (tree decl, tree pattern_decl, tree args, + tsubst_flags_t complain, tree in_decl, tree *first, + unsigned int *cnt) +{ + tree decl2, decl3, prev = decl; + *cnt = 0; + gcc_assert (DECL_NAME (decl) == NULL_TREE); + for (decl2 = DECL_CHAIN (pattern_decl); + decl2 + && VAR_P (decl2) + && DECL_DECOMPOSITION_P (decl2) + && DECL_NAME (decl2); + decl2 = DECL_CHAIN (decl2)) + { + (*cnt)++; + gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2)); + tree v = DECL_VALUE_EXPR (decl2); + DECL_HAS_VALUE_EXPR_P (decl2) = 0; + SET_DECL_VALUE_EXPR (decl2, NULL_TREE); + decl3 = tsubst (decl2, args, complain, in_decl); + SET_DECL_VALUE_EXPR (decl2, v); + DECL_HAS_VALUE_EXPR_P (decl2) = 1; + if (VAR_P (decl3)) + DECL_TEMPLATE_INSTANTIATED (decl3) = 1; + maybe_push_decl (decl3); + if (error_operand_p (decl3)) + decl = error_mark_node; + else if (decl != error_mark_node + && DECL_CHAIN (decl3) != prev) + { + gcc_assert (errorcount); + decl = error_mark_node; + } + else + prev = decl3; + } + *first = prev; + return decl; +} + /* Like tsubst_copy for expressions, etc. but also does semantic processing. */ @@ -15454,6 +15503,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (pattern_decl)); cp_finish_decl (decl, init, const_init, NULL_TREE, 0); + if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) + { + unsigned int cnt; + tree first; + decl = tsubst_decomp_names (decl, pattern_decl, args, + complain, in_decl, &first, + &cnt); + if (decl != error_mark_node) + cp_finish_decomp (decl, first, cnt); + } } } } @@ -15481,7 +15540,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, decl = tsubst (decl, args, complain, in_decl); maybe_push_decl (decl); expr = RECUR (RANGE_FOR_EXPR (t)); - stmt = cp_convert_range_for (stmt, decl, expr, RANGE_FOR_IVDEP (t)); + if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) + { + unsigned int cnt; + tree first; + decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args, + complain, in_decl, &first, &cnt); + stmt = cp_convert_range_for (stmt, decl, expr, first, cnt, + RANGE_FOR_IVDEP (t)); + } + else + stmt = cp_convert_range_for (stmt, decl, expr, NULL_TREE, 0, + RANGE_FOR_IVDEP (t)); RECUR (RANGE_FOR_BODY (t)); finish_for_stmt (stmt); } @@ -24800,7 +24870,15 @@ do_auto_deduction (tree type, tree init, tree auto_node, init = resolve_nondeduced_context (init, complain); - if (AUTO_IS_DECLTYPE (auto_node)) + if (context == adc_decomp_type + && auto_node == type + && init != error_mark_node + && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) + /* [dcl.decomp]/1 - if decomposition declaration has no ref-qualifiers + and initializer has array type, deduce cv-qualified array type. */ + return cp_build_qualified_type_real (TREE_TYPE (init), TYPE_QUALS (type), + complain); + else if (AUTO_IS_DECLTYPE (auto_node)) { bool id = (DECL_P (init) || ((TREE_CODE (init) == COMPONENT_REF @@ -24885,6 +24963,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, error("placeholder constraints not satisfied"); break; case adc_variable_type: + case adc_decomp_type: error ("deduced initializer does not satisfy " "placeholder constraints"); break; @@ -24893,7 +24972,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, "placeholder constraints"); break; case adc_requirement: - error ("deduced expression type does not saatisy " + error ("deduced expression type does not satisfy " "placeholder constraints"); break; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d390bf47469..0164f2e5c74 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8873,6 +8873,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, if (identifier_p (expr)) expr = lookup_name (expr); + if (VAR_P (expr) && DECL_HAS_VALUE_EXPR_P (expr)) + expr = DECL_VALUE_EXPR (expr); + if (INDIRECT_REF_P (expr)) /* This can happen when the expression is, e.g., "a.b". Just look at the underlying operand. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7872dd29cf8..c59543768a8 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -142,6 +142,9 @@ lvalue_kind (const_tree ref) return clk_none; /* FALLTHRU */ case VAR_DECL: + if (DECL_HAS_VALUE_EXPR_P (ref)) + return lvalue_kind (DECL_VALUE_EXPR (CONST_CAST_TREE (ref))); + if (TREE_READONLY (ref) && ! TREE_STATIC (ref) && DECL_LANG_SPECIFIC (ref) && DECL_IN_AGGR_P (ref)) @@ -1012,6 +1015,13 @@ tree cp_build_reference_type (tree to_type, bool rval) { tree lvalue_ref, t; + + if (TREE_CODE (to_type) == REFERENCE_TYPE) + { + rval = rval && TYPE_REF_IS_RVALUE (to_type); + to_type = TREE_TYPE (to_type); + } + lvalue_ref = build_reference_type (to_type); if (!rval) return lvalue_ref; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 24ca1b52410..2d8b7b10440 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1885,6 +1885,12 @@ is_bitfield_expr_with_lowered_type (const_tree exp) return DECL_BIT_FIELD_TYPE (field); } + case VAR_DECL: + if (DECL_HAS_VALUE_EXPR_P (exp)) + return is_bitfield_expr_with_lowered_type (DECL_VALUE_EXPR + (CONST_CAST_TREE (exp))); + return NULL_TREE; + CASE_CONVERT: if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0))) == TYPE_MAIN_VARIANT (TREE_TYPE (exp))) diff --git a/gcc/match.pd b/gcc/match.pd index 29ddcd82a18..79a418fa31e 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2547,8 +2547,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (with { int equal = 2; - if (decl_in_symtab_p (base0) - && decl_in_symtab_p (base1)) + /* Punt in GENERIC on variables with value expressions; + the value expressions might point to fields/elements + of other vars etc. */ + if (GENERIC + && ((VAR_P (base0) && DECL_HAS_VALUE_EXPR_P (base0)) + || (VAR_P (base1) && DECL_HAS_VALUE_EXPR_P (base1)))) + ; + else if (decl_in_symtab_p (base0) + && decl_in_symtab_p (base1)) equal = symtab_node::get_create (base0) ->equal_address_to (symtab_node::get_create (base1)); else if ((DECL_P (base0) diff --git a/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C b/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C index 3510aac908f..d2e538236bd 100644 --- a/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C +++ b/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C @@ -15,7 +15,7 @@ CHECK (xor_eq); // { dg-error "before .xor_eq. token" } #undef CHECK #define CHECK(x) int x - CHECK (<:); // { dg-error "before .<:. token" } + CHECK (<:); // { dg-error "" } CHECK (:>); // { dg-error "before .:>. token" } #undef CHECK #define CHECK(x) x