From 0935784671e347118c6bf7629852ba50e9466a85 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 2 Jul 2008 11:38:50 -0400 Subject: [PATCH] Implement WG21 N2672, Initializer List proposed wording gcc/cp/ChangeLog: 2008-07-02 Jason Merrill Implement WG21 N2672, Initializer List proposed wording * cp-tree.h (enum cp_tree_index): Add CPTI_INIT_LIST_TYPE. (struct lang_type_class): Add has_list_ctor bitfield. (TYPE_HAS_LIST_CTOR): New macro. (BRACE_ENCLOSED_INITIALIZER_P): Expect init_list_type_node. (CONSTRUCTOR_IS_DIRECT_INIT): New macro. (LOOKUP_NO_NARROWING): New macro. (LOOKUP_NO_COPY_CTOR_CONVERSION): New macro. * parser.c (cp_parse_braced_list): Split out from... (cp_parser_initializer_clause): ...here. (cp_parser_postfix_expression): Build up CONSTRUCTOR for compound literal here. (cp_lexer_next_token_is_not_keyword): New fn. (cp_parser_parenthesized_expression_list): Handle { }. (cp_parser_new_expression, cp_parser_new_initializer): Likewise. (cp_parser_assignment_expression, cp_parser_condition): Likewise. (cp_parser_jump_statement, cp_parser_simple_declaration): Likewise. (cp_parser_mem_initializer, cp_parser_init_declarator): Likewise. (cp_parser_initializer, cp_parser_functional_cast): Likewise. (cp_parser_omp_for_loop, cp_parser_cache_group): Likewise. (cp_parser_save_member_function_body): Likewise. * call.c (conversion_kind): Add ck_list, ck_aggr. (struct conversion): Add check_narrowing bitfield, conversion list. (build_list_conv): New fn. (build_aggr_conv): New fn. (implicit_conversion): Call them. (standard_conversion): Set check_narrowing if appropriate. (add_function_candidate): Handle LOOKUP_NO_COPY_CTOR_CONVERSION. (build_user_type_conversion_1): When converting from an init list, we allow additional conversions except when calling a copy ctor. (convert_like_real): Calling an explicit ctor for an init list is ill-formed. Handle ck_list and ck_addr. Check narrowing. (build_new_method_call): If CONSTRUCTOR_IS_DIRECT_INIT is set and class doesn't have a list ctor, break the {} into a TREE_LIST. (compare_ics): ck_list is better than other UDCs. (set_up_extended_ref_temp): Split out from initialize_reference. (is_std_init_list): New fn. (is_list_ctor): New fn. * decl.c (cxx_init_decl_processing): Create init_list_type_node. (reshape_init_array_1): Pass it to build_constructor. (reshape_init_class): Ditto. (initialize_artificial_var): Pass the appropriate type. (build_aggr_init_full_exprs): Split out from... (check_initializer): ...here. Handle new semantics. (build_init_list_var_init): New subroutine of check_initializer. (grokdeclarator): Converting constructors can have more than one parm. (grok_special_member_properties): Set TYPE_HAS_LIST_CTOR. * init.c (expand_default_init): Only do digest_init for aggregates. * rtti.c (tinfo_base_init): Pass init_list_type_node to build_constructor_from_list. (generic_initializer, ptr_initializer): Ditto. (ptm_initializer, class_initializer): Ditto. (get_pseudo_ti_init): Ditto. * error.c (dump_type): Handle init_list_type_node. (maybe_warn_cpp0x): New fn. (maybe_varn_variadic_templates): Call it. * cvt.c (ocp_convert): Handle conversion from { }. * tree.c (build_array_of_n_type): New fn. * typeck2.c (store_init_value): Use init_list_type_node. (digest_init): Likewise. (check_narrowing): New fn. * semantics.c: (finish_compound_literal): Take CONSTRUCTOR instead of vector of constructor elts. Handle non-aggregate types. Make constant literals static. * pt.c: (tsubst_copy_and_build): Adjust. (unify): Handle { }. * name-lookup.c (arg_assoc_type): Handle init_list_type_node. gcc/ChangeLog: 2008-07-02 Jason Merrill * tree.c (ctor_to_list): New fn. * tree.h: Declare it. (CONSTRUCTOR_ELT): New macro. (CONSTRUCTOR_NELTS): New macro. libstdc++-v3/ChangeLog: 2008-07-02 Jason Merrill * libsupc++/initializer_list: New file. * include/bits/stl_map.h (insert(initializer_list)): New method. From-SVN: r137361 --- gcc/ChangeLog | 7 + gcc/cp/ChangeLog | 70 +++++ gcc/cp/call.c | 368 +++++++++++++++++++----- gcc/cp/cp-tree.h | 30 +- gcc/cp/cvt.c | 6 +- gcc/cp/decl.c | 173 ++++++----- gcc/cp/error.c | 18 +- gcc/cp/init.c | 4 +- gcc/cp/name-lookup.c | 3 +- gcc/cp/parser.c | 307 ++++++++++++++------ gcc/cp/pt.c | 37 ++- gcc/cp/rtti.c | 14 +- gcc/cp/semantics.c | 34 ++- gcc/cp/tree.c | 8 + gcc/cp/typeck2.c | 85 +++++- gcc/testsuite/g++.dg/cpp0x/initlist1.C | 69 +++++ gcc/testsuite/g++.dg/cpp0x/initlist2.C | 32 +++ gcc/testsuite/g++.dg/cpp0x/initlist3.C | 11 + gcc/testsuite/g++.dg/cpp0x/initlist4.C | 32 +++ gcc/testsuite/g++.dg/cpp0x/initlist5.C | 21 ++ gcc/testsuite/g++.dg/cpp0x/initlist6.C | 30 ++ gcc/testsuite/g++.dg/inherit/error4.C | 6 +- gcc/testsuite/g++.dg/init/brace2.C | 2 +- gcc/testsuite/g++.dg/init/brace6.C | 6 +- gcc/testsuite/g++.dg/parse/crash36.C | 2 +- gcc/testsuite/g++.dg/parse/ctor3.C | 2 +- gcc/tree.c | 20 ++ gcc/tree.h | 7 + libstdc++-v3/ChangeLog | 5 + libstdc++-v3/include/bits/stl_map.h | 13 + libstdc++-v3/libsupc++/initializer_list | 64 +++++ 31 files changed, 1212 insertions(+), 274 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist6.C create mode 100644 libstdc++-v3/libsupc++/initializer_list diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 916d1b0244a..fad92a66f41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2008-07-02 Jason Merrill + + * tree.c (ctor_to_list): New fn. + * tree.h: Declare it. + (CONSTRUCTOR_ELT): New macro. + (CONSTRUCTOR_NELTS): New macro. + 2008-07-02 Richard Guenther * tree-ssa-structalias.c (struct variable_info): Reorder diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8aff706f9db..3bf8c97596d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,73 @@ +2008-07-02 Jason Merrill + + Implement WG21 N2672, Initializer List proposed wording + * cp-tree.h (enum cp_tree_index): Add CPTI_INIT_LIST_TYPE. + (struct lang_type_class): Add has_list_ctor bitfield. + (TYPE_HAS_LIST_CTOR): New macro. + (BRACE_ENCLOSED_INITIALIZER_P): Expect init_list_type_node. + (CONSTRUCTOR_IS_DIRECT_INIT): New macro. + (LOOKUP_NO_NARROWING): New macro. + (LOOKUP_NO_COPY_CTOR_CONVERSION): New macro. + * parser.c (cp_parse_braced_list): Split out from... + (cp_parser_initializer_clause): ...here. + (cp_parser_postfix_expression): Build up CONSTRUCTOR for compound + literal here. + (cp_lexer_next_token_is_not_keyword): New fn. + (cp_parser_parenthesized_expression_list): Handle { }. + (cp_parser_new_expression, cp_parser_new_initializer): Likewise. + (cp_parser_assignment_expression, cp_parser_condition): Likewise. + (cp_parser_jump_statement, cp_parser_simple_declaration): Likewise. + (cp_parser_mem_initializer, cp_parser_init_declarator): Likewise. + (cp_parser_initializer, cp_parser_functional_cast): Likewise. + (cp_parser_omp_for_loop, cp_parser_cache_group): Likewise. + (cp_parser_save_member_function_body): Likewise. + * call.c (conversion_kind): Add ck_list, ck_aggr. + (struct conversion): Add check_narrowing bitfield, conversion list. + (build_list_conv): New fn. + (build_aggr_conv): New fn. + (implicit_conversion): Call them. + (standard_conversion): Set check_narrowing if appropriate. + (add_function_candidate): Handle LOOKUP_NO_COPY_CTOR_CONVERSION. + (build_user_type_conversion_1): When converting from an init list, + we allow additional conversions except when calling a copy ctor. + (convert_like_real): Calling an explicit ctor for an init list is + ill-formed. Handle ck_list and ck_addr. Check narrowing. + (build_new_method_call): If CONSTRUCTOR_IS_DIRECT_INIT is set and + class doesn't have a list ctor, break the {} into a TREE_LIST. + (compare_ics): ck_list is better than other UDCs. + (set_up_extended_ref_temp): Split out from initialize_reference. + (is_std_init_list): New fn. + (is_list_ctor): New fn. + * decl.c (cxx_init_decl_processing): Create init_list_type_node. + (reshape_init_array_1): Pass it to build_constructor. + (reshape_init_class): Ditto. + (initialize_artificial_var): Pass the appropriate type. + (build_aggr_init_full_exprs): Split out from... + (check_initializer): ...here. Handle new semantics. + (build_init_list_var_init): New subroutine of check_initializer. + (grokdeclarator): Converting constructors can have more than one parm. + (grok_special_member_properties): Set TYPE_HAS_LIST_CTOR. + * init.c (expand_default_init): Only do digest_init for aggregates. + * rtti.c (tinfo_base_init): Pass init_list_type_node to + build_constructor_from_list. + (generic_initializer, ptr_initializer): Ditto. + (ptm_initializer, class_initializer): Ditto. + (get_pseudo_ti_init): Ditto. + * error.c (dump_type): Handle init_list_type_node. + (maybe_warn_cpp0x): New fn. + (maybe_varn_variadic_templates): Call it. + * cvt.c (ocp_convert): Handle conversion from { }. + * tree.c (build_array_of_n_type): New fn. + * typeck2.c (store_init_value): Use init_list_type_node. + (digest_init): Likewise. + (check_narrowing): New fn. + * semantics.c: (finish_compound_literal): Take CONSTRUCTOR instead + of vector of constructor elts. Handle non-aggregate types. Make + constant literals static. + * pt.c: (tsubst_copy_and_build): Adjust. + (unify): Handle { }. + * name-lookup.c (arg_assoc_type): Handle init_list_type_node. + 2008-07-01 Daniel Jacobowitz * typeck.c (comp_ptr_ttypes_real): Use vector_targets_convertible_p. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7f4c0168483..d41465db638 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -54,6 +54,8 @@ typedef enum conversion_kind { ck_ref_bind, ck_user, ck_ambig, + ck_list, + ck_aggr, ck_rvalue } conversion_kind; @@ -96,6 +98,7 @@ struct conversion { being bound to an lvalue expression or an rvalue reference is being bound to an rvalue expression. */ BOOL_BITFIELD rvaluedness_matches_p: 1; + BOOL_BITFIELD check_narrowing: 1; /* The type of the expression resulting from the conversion. */ tree type; union { @@ -107,6 +110,8 @@ struct conversion { /* The expression at the beginning of the conversion chain. This variant is used only if KIND is ck_identity or ck_ambig. */ tree expr; + /* The array of conversions for an initializer_list. */ + conversion **list; } u; /* The function candidate corresponding to this conversion sequence. This field is only used if KIND is ck_user. */ @@ -174,6 +179,7 @@ static conversion *implicit_conversion (tree, tree, tree, bool, int); static conversion *standard_conversion (tree, tree, tree, bool, int); static conversion *reference_binding (tree, tree, tree, bool, int); static conversion *build_conv (conversion_kind, tree, conversion *); +static conversion *build_list_conv (tree, tree, int); static bool is_subseq (conversion *, conversion *); static conversion *maybe_handle_ref_bind (conversion **); static void maybe_handle_implicit_object (conversion **); @@ -529,9 +535,8 @@ build_conv (conversion_kind code, tree type, conversion *from) conversion *t; conversion_rank rank = CONVERSION_RANK (from); - /* We can't use buildl1 here because CODE could be USER_CONV, which - takes two arguments. In that case, the caller is responsible for - filling in the second argument. */ + /* Note that the caller is responsible for filling in t->cand for + user-defined conversions. */ t = alloc_conversion (code); t->type = type; t->u.next = from; @@ -561,6 +566,83 @@ build_conv (conversion_kind code, tree type, conversion *from) return t; } +/* Represent a conversion from CTOR, a braced-init-list, to TYPE, a + specialization of std::initializer_list, if such a conversion is + possible. */ + +static conversion * +build_list_conv (tree type, tree ctor, int flags) +{ + tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (type), 0); + unsigned len = CONSTRUCTOR_NELTS (ctor); + conversion **subconvs = alloc_conversions (len); + conversion *t; + unsigned i; + tree val; + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), i, val) + { + conversion *sub + = implicit_conversion (elttype, TREE_TYPE (val), val, + false, flags); + if (sub == NULL) + return NULL; + + subconvs[i] = sub; + } + + t = alloc_conversion (ck_list); + t->type = type; + t->u.list = subconvs; + t->rank = cr_exact; + + for (i = 0; i < len; ++i) + { + conversion *sub = subconvs[i]; + if (sub->rank > t->rank) + t->rank = sub->rank; + if (sub->user_conv_p) + t->user_conv_p = true; + if (sub->bad_p) + t->bad_p = true; + } + + return t; +} + +/* Represent a conversion from CTOR, a braced-init-list, to TYPE, an + aggregate class, if such a conversion is possible. */ + +static conversion * +build_aggr_conv (tree type, tree ctor, int flags) +{ + unsigned HOST_WIDE_INT i = 0; + conversion *c; + tree field = TYPE_FIELDS (type); + + for (; field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + if (i < CONSTRUCTOR_NELTS (ctor)) + { + constructor_elt *ce = CONSTRUCTOR_ELT (ctor, i); + if (!can_convert_arg (TREE_TYPE (field), TREE_TYPE (ce->value), + ce->value, flags)) + return NULL; + } + else if (build_value_init (TREE_TYPE (field)) == error_mark_node) + return NULL; + } + + c = alloc_conversion (ck_aggr); + c->type = type; + c->rank = cr_exact; + c->user_conv_p = true; + c->u.next = NULL; + return c; +} + /* Build a representation of the identity conversion from EXPR to itself. The TYPE should match the type of EXPR, if EXPR is non-NULL. */ @@ -865,6 +947,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, else return NULL; + if (flags & LOOKUP_NO_NARROWING) + conv->check_narrowing = true; + return conv; } @@ -1296,6 +1381,10 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, if (conv) return conv; + if (is_std_init_list (to) && expr + && BRACE_ENCLOSED_INITIALIZER_P (expr)) + return build_list_conv (to, expr, flags); + if (expr != NULL_TREE && (MAYBE_CLASS_TYPE_P (from) || MAYBE_CLASS_TYPE_P (to)) @@ -1305,6 +1394,11 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, int convflags = ((flags & LOOKUP_NO_TEMP_BIND) |LOOKUP_ONLYCONVERTING); + if (CLASS_TYPE_P (to) + && !CLASSTYPE_NON_AGGREGATE (complete_type (to)) + && BRACE_ENCLOSED_INITIALIZER_P (expr)) + return build_aggr_conv (to, expr, flags); + cand = build_user_type_conversion_1 (to, expr, convflags); if (cand) conv = cand->second_conv; @@ -1431,6 +1525,7 @@ add_function_candidate (struct z_candidate **candidates, if (parmnode) { tree parmtype = TREE_VALUE (parmnode); + int lflags = flags; /* The type of the implicit object parameter ('this') for overload resolution is not always the same as for the @@ -1449,8 +1544,12 @@ add_function_candidate (struct z_candidate **candidates, parmtype = build_pointer_type (parmtype); } + if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION) + && ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn)) + lflags |= LOOKUP_NO_CONVERSION; + t = implicit_conversion (parmtype, argtype, arg, - /*c_cast_p=*/false, flags); + /*c_cast_p=*/false, lflags); } else { @@ -2607,7 +2706,18 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) ctors = BASELINK_FUNCTIONS (ctors); t = build_int_cst (build_pointer_type (totype), 0); - args = build_tree_list (NULL_TREE, expr); + if (BRACE_ENCLOSED_INITIALIZER_P (expr) + && !TYPE_HAS_LIST_CTOR (totype)) + { + args = ctor_to_list (expr); + /* We still allow more conversions within an init-list. */ + flags = ((flags & ~LOOKUP_NO_CONVERSION) + /* But not for the copy ctor. */ + |LOOKUP_NO_COPY_CTOR_CONVERSION + |LOOKUP_NO_NARROWING); + } + else + args = build_tree_list (NULL_TREE, expr); /* We should never try to call the abstract or base constructor from here. */ gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors)) @@ -2617,7 +2727,8 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) for (; ctors; ctors = OVL_NEXT (ctors)) { tree ctor = OVL_CURRENT (ctors); - if (DECL_NONCONVERTING_P (ctor)) + if (DECL_NONCONVERTING_P (ctor) + && !BRACE_ENCLOSED_INITIALIZER_P (expr)) continue; if (TREE_CODE (ctor) == TEMPLATE_DECL) @@ -4443,6 +4554,17 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, tree convfn = cand->fn; unsigned i; + /* When converting from an init list we consider explicit + constructors, but actually trying to call one is an error. */ + if (DECL_NONCONVERTING_P (convfn)) + { + if (complain & tf_error) + error ("converting to %qT from initializer list would use " + "explicit constructor %qD", totype, convfn); + else + return error_mark_node; + } + /* Set user_conv_p on the argument conversions, so rvalue/base handling knows not to allow any more UDCs. */ for (i = 0; i < cand->num_convs; ++i) @@ -4478,6 +4600,44 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, return build_user_type_conversion (totype, convs->u.expr, LOOKUP_NORMAL); + case ck_list: + { + /* Conversion to std::initializer_list. */ + tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0); + tree new_ctor = build_constructor (init_list_type_node, NULL); + unsigned len = CONSTRUCTOR_NELTS (expr); + tree array, parms, val; + unsigned ix; + + /* Convert all the elements. */ + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) + { + tree sub = convert_like_real (convs->u.list[ix], val, fn, argnum, + 1, false, false, complain); + if (sub == error_mark_node) + return sub; + check_narrowing (TREE_TYPE (sub), val); + CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor), NULL_TREE, sub); + } + /* Build up the array. */ + elttype = cp_build_qualified_type + (elttype, TYPE_QUALS (elttype) | TYPE_QUAL_CONST); + array = build_array_of_n_type (elttype, len); + array = finish_compound_literal (array, new_ctor); + + parms = build_tree_list (NULL_TREE, size_int (len)); + parms = tree_cons (NULL_TREE, decay_conversion (array), parms); + /* Call the private constructor. */ + push_deferring_access_checks (dk_no_check); + new_ctor = build_special_member_call + (NULL_TREE, complete_ctor_identifier, parms, totype, 0, complain); + pop_deferring_access_checks (); + return build_cplus_new (totype, new_ctor); + } + + case ck_aggr: + return get_target_expr (digest_init (totype, expr)); + default: break; }; @@ -4625,6 +4785,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, break; } + if (convs->check_narrowing) + check_narrowing (totype, expr); + if (issue_conversion_warnings) expr = convert_and_check (totype, expr); else @@ -5626,6 +5789,18 @@ build_new_method_call (tree instance, tree fns, tree args, if (DECL_DESTRUCTOR_P (fn)) name = complete_dtor_identifier; + /* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form + initializer, not T({ }). If the type doesn't have a list ctor, + break apart the list into separate ctor args. */ + if (DECL_CONSTRUCTOR_P (fn) && args + && BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (args)) + && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (args)) + && !TYPE_HAS_LIST_CTOR (basetype)) + { + gcc_assert (TREE_CHAIN (args) == NULL_TREE); + args = ctor_to_list (TREE_VALUE (args)); + } + class_type = (conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE); mem_args = tree_cons (NULL_TREE, instance_ptr, args); @@ -5977,13 +6152,26 @@ compare_ics (conversion *ics1, conversion *ics2) conversion *t1; conversion *t2; - for (t1 = ics1; t1->kind != ck_user; t1 = t1->u.next) - if (t1->kind == ck_ambig) + for (t1 = ics1; t1->kind != ck_user && t1->kind != ck_list; t1 = t1->u.next) + if (t1->kind == ck_ambig || t1->kind == ck_aggr) return 0; - for (t2 = ics2; t2->kind != ck_user; t2 = t2->u.next) - if (t2->kind == ck_ambig) + for (t2 = ics2; t2->kind != ck_user && t2->kind != ck_list; t2 = t2->u.next) + if (t2->kind == ck_ambig || t2->kind == ck_aggr) return 0; + /* Conversion to std::initializer_list is better than other + user-defined conversions. */ + if (t1->kind == ck_list + || t2->kind == ck_list) + { + if (t2->kind != ck_list) + return 1; + else if (t1->kind != ck_list) + return -1; + else + return 0; + } + if (t1->cand->fn != t2->cand->fn) return 0; @@ -6815,6 +7003,76 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type) return var; } +/* EXPR is the initializer for a variable DECL of reference or + std::initializer_list type. Create, push and return a new VAR_DECL + for the initializer so that it will live as long as DECL. Any + cleanup for the new variable is returned through CLEANUP, and the + code to initialize the new variable is returned through INITP. */ + +tree +set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp) +{ + tree init; + tree type; + tree var; + + /* Create the temporary variable. */ + type = TREE_TYPE (expr); + var = make_temporary_var_for_ref_to_temp (decl, type); + layout_decl (var, 0); + /* If the rvalue is the result of a function call it will be + a TARGET_EXPR. If it is some other construct (such as a + member access expression where the underlying object is + itself the result of a function call), turn it into a + TARGET_EXPR here. It is important that EXPR be a + TARGET_EXPR below since otherwise the INIT_EXPR will + attempt to make a bitwise copy of EXPR to initialize + VAR. */ + if (TREE_CODE (expr) != TARGET_EXPR) + expr = get_target_expr (expr); + /* Create the INIT_EXPR that will initialize the temporary + variable. */ + init = build2 (INIT_EXPR, type, var, expr); + if (at_function_scope_p ()) + { + add_decl_expr (var); + + if (TREE_STATIC (var)) + init = add_stmt_to_compound (init, register_dtor_fn (var)); + else + *cleanup = cxx_maybe_build_cleanup (var); + + /* We must be careful to destroy the temporary only + after its initialization has taken place. If the + initialization throws an exception, then the + destructor should not be run. We cannot simply + transform INIT into something like: + + (INIT, ({ CLEANUP_STMT; })) + + because emit_local_var always treats the + initializer as a full-expression. Thus, the + destructor would run too early; it would run at the + end of initializing the reference variable, rather + than at the end of the block enclosing the + reference variable. + + The solution is to pass back a cleanup expression + which the caller is responsible for attaching to + the statement tree. */ + } + else + { + rest_of_decl_compilation (var, /*toplev=*/1, at_eof); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + static_aggregates = tree_cons (NULL_TREE, var, + static_aggregates); + } + + *initp = init; + return var; +} + /* Convert EXPR to the indicated reference TYPE, in a way suitable for initializing a variable of that TYPE. If DECL is non-NULL, it is the VAR_DECL being initialized with the EXPR. (In that case, the @@ -6919,60 +7177,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup) if (!real_lvalue_p (expr)) { tree init; - tree type; - - /* Create the temporary variable. */ - type = TREE_TYPE (expr); - var = make_temporary_var_for_ref_to_temp (decl, type); - layout_decl (var, 0); - /* If the rvalue is the result of a function call it will be - a TARGET_EXPR. If it is some other construct (such as a - member access expression where the underlying object is - itself the result of a function call), turn it into a - TARGET_EXPR here. It is important that EXPR be a - TARGET_EXPR below since otherwise the INIT_EXPR will - attempt to make a bitwise copy of EXPR to initialize - VAR. */ - if (TREE_CODE (expr) != TARGET_EXPR) - expr = get_target_expr (expr); - /* Create the INIT_EXPR that will initialize the temporary - variable. */ - init = build2 (INIT_EXPR, type, var, expr); - if (at_function_scope_p ()) - { - add_decl_expr (var); - - if (TREE_STATIC (var)) - init = add_stmt_to_compound (init, register_dtor_fn (var)); - else - *cleanup = cxx_maybe_build_cleanup (var); - - /* We must be careful to destroy the temporary only - after its initialization has taken place. If the - initialization throws an exception, then the - destructor should not be run. We cannot simply - transform INIT into something like: - - (INIT, ({ CLEANUP_STMT; })) - - because emit_local_var always treats the - initializer as a full-expression. Thus, the - destructor would run too early; it would run at the - end of initializing the reference variable, rather - than at the end of the block enclosing the - reference variable. - - The solution is to pass back a cleanup expression - which the caller is responsible for attaching to - the statement tree. */ - } - else - { - rest_of_decl_compilation (var, /*toplev=*/1, at_eof); - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) - static_aggregates = tree_cons (NULL_TREE, var, - static_aggregates); - } + var = set_up_extended_ref_temp (decl, expr, cleanup, &init); /* Use its address to initialize the reference variable. */ expr = build_address (var); if (base_conv_type) @@ -7003,4 +7208,39 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup) return expr; } +/* Returns true iff TYPE is some variant of std::initializer_list. */ + +bool +is_std_init_list (tree type) +{ + return (CLASS_TYPE_P (type) + && CP_TYPE_CONTEXT (type) == std_node + && strcmp (TYPE_NAME_STRING (type), "initializer_list") == 0); +} + +/* Returns true iff DECL is a list constructor: i.e. a constructor which + will accept an argument list of a single std::initializer_list. */ + +bool +is_list_ctor (tree decl) +{ + tree args = FUNCTION_FIRST_USER_PARMTYPE (decl); + tree arg; + + if (!args || args == void_list_node) + return false; + + arg = non_reference (TREE_VALUE (args)); + if (!is_std_init_list (arg)) + return false; + + args = TREE_CHAIN (args); + + if (args && args != void_list_node && !TREE_PURPOSE (args)) + /* There are more non-defaulted parms. */ + return false; + + return true; +} + #include "gt-cp-call.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d090d8ff0e2..ed6ae0e810a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -59,6 +59,7 @@ struct diagnostic_info; TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) TYPE_REF_IS_RVALUE (in REFERENCE_TYPE) ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute) + CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -572,6 +573,7 @@ enum cp_tree_index CPTI_CLASS_TYPE, CPTI_UNKNOWN_TYPE, + CPTI_INIT_LIST_TYPE, CPTI_VTBL_TYPE, CPTI_VTBL_PTR_TYPE, CPTI_STD, @@ -637,6 +639,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define class_type_node cp_global_trees[CPTI_CLASS_TYPE] #define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE] +#define init_list_type_node cp_global_trees[CPTI_INIT_LIST_TYPE] #define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE] #define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE] #define std_node cp_global_trees[CPTI_STD] @@ -1126,6 +1129,7 @@ struct lang_type_class GTY(()) unsigned has_complex_assign_ref : 1; unsigned non_aggregate : 1; unsigned has_complex_dflt : 1; + unsigned has_list_ctor : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -1134,7 +1138,7 @@ struct lang_type_class GTY(()) /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 11; + unsigned dummy : 10; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -1248,6 +1252,10 @@ struct lang_type GTY(()) #define TYPE_HAS_CONST_INIT_REF(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->has_const_init_ref) +/* Nonzero if this class has an X(initializer_list) constructor. */ +#define TYPE_HAS_LIST_CTOR(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->has_list_ctor) + /* Nonzero if this class defines an overloaded operator new. (An operator new [] doesn't count.) */ #define TYPE_HAS_NEW_OPERATOR(NODE) \ @@ -2713,7 +2721,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* True if NODE is a brace-enclosed initializer. */ #define BRACE_ENCLOSED_INITIALIZER_P(NODE) \ - (TREE_CODE (NODE) == CONSTRUCTOR && !TREE_TYPE (NODE)) + (TREE_CODE (NODE) == CONSTRUCTOR && TREE_TYPE (NODE) == init_list_type_node) /* True if NODE is a compound-literal, i.e., a brace-enclosed initializer cast to a particular type. */ @@ -2725,6 +2733,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) CONSTRUCTOR_ELTS (NODE)) \ && !TREE_HAS_CONSTRUCTOR (NODE)) +/* True if NODE is a init-list used as a direct-initializer, i.e. + B b{1,2}, not B b({1,2}) or B b = {1,2}. */ +#define CONSTRUCTOR_IS_DIRECT_INIT(NODE) (TREE_LANG_FLAG_0 (CONSTRUCTOR_CHECK (NODE))) + /* Nonzero means that an object of this type can not be initialized using an initializer list. */ #define CLASSTYPE_NON_AGGREGATE(NODE) \ @@ -3688,6 +3700,11 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG }; #define LOOKUP_HIDDEN (LOOKUP_PREFER_NAMESPACES << 1) /* Prefer that the lvalue be treated as an rvalue. */ #define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1) +/* We're inside an init-list, so narrowing conversions are ill-formed. */ +#define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1) +/* Avoid user-defined conversions for the first parameter of a copy + constructor. */ +#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1) #define LOOKUP_NAMESPACES_ONLY(F) \ (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) @@ -4084,6 +4101,7 @@ extern tree cxx_type_promotes_to (tree); extern tree type_passed_as (tree); extern tree convert_for_arg_passing (tree, tree); extern bool is_properly_derived_from (tree, tree); +extern tree set_up_extended_ref_temp (tree, tree, tree *, tree *); extern tree initialize_reference (tree, tree, tree, tree *); extern tree make_temporary_var_for_ref_to_temp (tree, tree); extern tree strip_top_quals (tree); @@ -4092,6 +4110,8 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); extern tree in_charge_arg_for_name (tree); extern tree build_cxx_call (tree, int, tree *); +extern bool is_std_init_list (tree); +extern bool is_list_ctor (tree); #ifdef ENABLE_CHECKING extern void validate_conversion_obstack (void); #endif /* ENABLE_CHECKING */ @@ -4311,6 +4331,7 @@ extern const char *language_to_string (enum languages); extern const char *class_key_or_enum_as_string (tree); extern void print_instantiation_context (void); extern void maybe_warn_variadic_templates (void); +extern void maybe_warn_cpp0x (const char *); /* in except.c */ extern void init_exception_processing (void); @@ -4622,7 +4643,7 @@ extern tree finish_increment_expr (tree, enum tree_code); extern tree finish_this_expr (void); extern tree finish_pseudo_destructor_expr (tree, tree, tree); extern tree finish_unary_op_expr (enum tree_code, tree); -extern tree finish_compound_literal (tree, VEC(constructor_elt,gc) *); +extern tree finish_compound_literal (tree, tree); extern tree finish_fname (tree); extern void finish_translation_unit (void); extern tree finish_template_type_parm (tree, tree); @@ -4707,6 +4728,7 @@ extern tree build_min_non_dep_call_list (tree, tree, tree); extern tree build_cplus_new (tree, tree); extern tree get_target_expr (tree); extern tree build_cplus_array_type (tree, tree); +extern tree build_array_of_n_type (tree, int); extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); extern tree build_qualified_name (tree, tree, tree, bool); @@ -4861,6 +4883,7 @@ extern void complete_type_check_abstract (tree); extern int abstract_virtuals_error (tree, tree); extern tree store_init_value (tree, tree); +extern void check_narrowing (tree, tree); extern tree digest_init (tree, tree); extern tree build_scoped_ref (tree, tree, tree *); extern tree build_x_arrow (tree); @@ -4882,6 +4905,7 @@ extern tree mangle_thunk (tree, int, tree, tree); extern tree mangle_conv_op_name_for_type (tree); extern tree mangle_guard_variable (tree); extern tree mangle_ref_init_variable (tree); +extern tree mangle_compound_literal (void); /* in dump.c */ extern bool cp_dump_tree (void *, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index b2c17c547db..70ef00a4fce 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -725,8 +725,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags) if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; - if ((flags & LOOKUP_ONLYCONVERTING) - && ! (MAYBE_CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype))) + if (BRACE_ENCLOSED_INITIALIZER_P (ctor)) + ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error); + else if ((flags & LOOKUP_ONLYCONVERTING) + && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype))) /* For copy-initialization, first we create a temp of the proper type with a user-defined conversion sequence, then we direct-initialize the target with the temp (see [dcl.init]). */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c6ae93e6104..a5a5574d7b4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3344,6 +3344,9 @@ cxx_init_decl_processing (void) TYPE_POINTER_TO (unknown_type_node) = unknown_type_node; TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node; + init_list_type_node = make_node (UNKNOWN_TYPE); + record_unknown_type (init_list_type_node, "init list"); + { /* Make sure we get a unique function type, so we can give its pointer type a name. (This wins for gdb.) */ @@ -4295,6 +4298,39 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) return NULL_TREE; } +/* Subroutine of check_initializer. We're initializing a DECL of + std::initializer_list TYPE from a braced-init-list INIT, and need to + extend the lifetime of the underlying array to match that of the decl, + just like for reference initialization. CLEANUP is as for + grok_reference_init. */ + +static tree +build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup) +{ + tree aggr_init, array, arrtype; + init = perform_implicit_conversion (type, init, tf_warning_or_error); + aggr_init = TARGET_EXPR_INITIAL (init); + init = build2 (INIT_EXPR, type, decl, init); + + array = AGGR_INIT_EXPR_ARG (aggr_init, 1); + arrtype = TREE_TYPE (array); + STRIP_NOPS (array); + gcc_assert (TREE_CODE (array) == ADDR_EXPR); + array = TREE_OPERAND (array, 0); + /* If the array is constant, finish_compound_literal already made it a + static variable and we don't need to do anything here. */ + if (decl && TREE_CODE (array) == TARGET_EXPR) + { + tree subinit; + tree var = set_up_extended_ref_temp (decl, array, cleanup, &subinit); + var = build_address (var); + var = convert (arrtype, var); + AGGR_INIT_EXPR_ARG (aggr_init, 1) = var; + init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init); + } + return init; +} + /* Designated initializers in arrays are not supported in GNU C++. The parser cannot detect this error since it does not know whether a given brace-enclosed initializer is for a class type or for an @@ -4573,7 +4609,7 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d) unsigned HOST_WIDE_INT index; /* The initializer for an array is always a CONSTRUCTOR. */ - new_init = build_constructor (NULL_TREE, NULL); + new_init = build_constructor (init_list_type_node, NULL); if (sized_array_p) { @@ -4668,7 +4704,7 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p) gcc_assert (CLASS_TYPE_P (type)); /* The initializer for a class is always a CONSTRUCTOR. */ - new_init = build_constructor (NULL_TREE, NULL); + new_init = build_constructor (init_list_type_node, NULL); field = next_initializable_field (TYPE_FIELDS (type)); if (!field) @@ -4926,6 +4962,26 @@ check_array_initializer (tree decl, tree type, tree init) return false; } +/* Subroutine of check_initializer; args are passed down from that function. + Set stmts_are_full_exprs_p to 1 across a call to build_aggr_init. */ + +static tree +build_aggr_init_full_exprs (tree decl, tree init, int flags) + +{ + int saved_stmts_are_full_exprs_p = 0; + if (building_stmt_tree ()) + { + saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); + current_stmt_tree ()->stmts_are_full_exprs_p = 1; + } + init = build_aggr_init (decl, init, flags, tf_warning_or_error); + if (building_stmt_tree ()) + current_stmt_tree ()->stmts_are_full_exprs_p = + saved_stmts_are_full_exprs_p; + return init; +} + /* Verify INIT (the initializer for DECL), and record the initialization in DECL_INITIAL, if appropriate. CLEANUP is as for grok_reference_init. @@ -4967,7 +5023,12 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) int init_len = VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)); if (SCALAR_TYPE_P (type)) { - if (init_len != 1) + if (init_len == 0) + { + maybe_warn_cpp0x ("extended initializer lists"); + init = build_zero_init (type, NULL_TREE, false); + } + else if (init_len != 1) { error ("scalar object %qD requires one element in initializer", decl); @@ -4975,15 +5036,6 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) return NULL_TREE; } } - else if ((cxx_dialect == cxx98) && !CP_AGGREGATE_TYPE_P (type)) - { - /* A non-aggregate that is not a scalar cannot be initialized - via an initializer-list in C++98. */ - error ("braces around initializer for non-aggregate type %qT", - type); - TREE_TYPE (decl) = error_mark_node; - return NULL_TREE; - } } if (TREE_CODE (decl) == CONST_DECL) @@ -5001,17 +5053,26 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) { /* Do not reshape constructors of vectors (they don't need to be reshaped. */ - if (TREE_CODE (init) == CONSTRUCTOR - && !COMPOUND_LITERAL_P (init) - && !TREE_TYPE (init)) /* ptrmemfunc */ + if (BRACE_ENCLOSED_INITIALIZER_P (init)) { - init = reshape_init (type, init); - - if ((*targetm.vector_opaque_p) (type)) + if (is_std_init_list (type)) + return build_init_list_var_init (decl, type, init, cleanup); + else if (TYPE_NON_AGGREGATE_CLASS (type)) + { + /* Don't reshape if the class has constructors. */ + if (cxx_dialect == cxx98) + error ("in C++98 %qD must be initialized by constructor, " + "not by %<{...}%>", + decl); + init = build_tree_list (NULL_TREE, init); + } + else if ((*targetm.vector_opaque_p) (type)) { error ("opaque vector types cannot be initialized"); init = error_mark_node; } + else + init = reshape_init (type, init); } /* If DECL has an array type without a specific bound, deduce the @@ -5021,60 +5082,26 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) if (type == error_mark_node) return NULL_TREE; - if (TREE_CODE (type) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (type)) - goto initialize_aggr; - else if (CLASS_TYPE_P (type)) + if (TYPE_NEEDS_CONSTRUCTING (type) + || (CLASS_TYPE_P (type) + && !BRACE_ENCLOSED_INITIALIZER_P (init))) + return build_aggr_init_full_exprs (decl, init, flags); + else if (TREE_CODE (init) != TREE_VEC) { - if (TREE_CODE (init) == CONSTRUCTOR) - { - if (TYPE_NON_AGGREGATE_CLASS (type)) - { - error ("%qD must be initialized by constructor, " - "not by %<{...}%>", - decl); - init = error_mark_node; - } - else - goto dont_use_constructor; - } - else - { - int saved_stmts_are_full_exprs_p; - - initialize_aggr: - saved_stmts_are_full_exprs_p = 0; - if (building_stmt_tree ()) - { - saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); - current_stmt_tree ()->stmts_are_full_exprs_p = 1; - } - init = build_aggr_init (decl, init, flags, tf_warning_or_error); - if (building_stmt_tree ()) - current_stmt_tree ()->stmts_are_full_exprs_p = - saved_stmts_are_full_exprs_p; - return init; - } - } - else - { - dont_use_constructor: - if (TREE_CODE (init) != TREE_VEC) - { - init_code = store_init_value (decl, init); - if (pedantic && TREE_CODE (type) == ARRAY_TYPE - && DECL_INITIAL (decl) - && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST - && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl))) - warning (0, "array %qD initialized by parenthesized string literal %qE", - decl, DECL_INITIAL (decl)); - init = NULL; - } + init_code = store_init_value (decl, init); + if (pedantic && TREE_CODE (type) == ARRAY_TYPE + && DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST + && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl))) + warning (0, "array %qD initialized by parenthesized string literal %qE", + decl, DECL_INITIAL (decl)); + init = NULL; } } else if (DECL_EXTERNAL (decl)) ; else if (TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type)) - goto initialize_aggr; + return build_aggr_init_full_exprs (decl, init, flags); else if (MAYBE_CLASS_TYPE_P (type)) { tree core_type = strip_array_types (type); @@ -5311,7 +5338,7 @@ initialize_artificial_var (tree decl, tree init) { gcc_assert (DECL_ARTIFICIAL (decl)); if (TREE_CODE (init) == TREE_LIST) - init = build_constructor_from_list (NULL_TREE, init); + init = build_constructor_from_list (TREE_TYPE (decl), init); gcc_assert (TREE_CODE (init) == CONSTRUCTOR); DECL_INITIAL (decl) = init; DECL_INITIALIZED_P (decl) = 1; @@ -8921,17 +8948,11 @@ grokdeclarator (const cp_declarator *declarator, DECL_NONCONVERTING_P (decl) = 1; else if (DECL_CONSTRUCTOR_P (decl)) { - /* The constructor can be called with exactly one - parameter if there is at least one parameter, and - any subsequent parameters have default arguments. + /* A constructor with no parms is not a conversion. Ignore any compiler-added parms. */ tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (decl); - if (arg_types == void_list_node - || (arg_types - && TREE_CHAIN (arg_types) - && TREE_CHAIN (arg_types) != void_list_node - && !TREE_PURPOSE (TREE_CHAIN (arg_types)))) + if (arg_types == void_list_node) DECL_NONCONVERTING_P (decl) = 1; } } @@ -9646,6 +9667,8 @@ grok_special_member_properties (tree decl) } else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; + else if (is_list_ctor (decl)) + TYPE_HAS_LIST_CTOR (class_type) = 1; } else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 55e620a6b54..80aa6e962d2 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -284,7 +284,10 @@ dump_type (tree t, int flags) switch (TREE_CODE (t)) { case UNKNOWN_TYPE: - pp_identifier (cxx_pp, ""); + if (t == init_list_type_node) + pp_identifier (cxx_pp, ""); + else + pp_identifier (cxx_pp, ""); break; case TREE_LIST: @@ -2674,13 +2677,20 @@ cp_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, report_diagnostic (&diagnostic); } -/* Warn about the use of variadic templates when appropriate. */ +/* Warn about the use of C++0x features when appropriate. */ void -maybe_warn_variadic_templates (void) +maybe_warn_cpp0x (const char* str) { if ((cxx_dialect == cxx98) && !in_system_header) /* We really want to suppress this warning in system headers, because libstdc++ uses variadic templates even when we aren't in C++0x mode. */ - pedwarn ("ISO C++ does not include variadic templates"); + pedwarn ("%s only available with -std=c++0x", str); +} + +/* Warn about the use of variadic templates when appropriate. */ +void +maybe_warn_variadic_templates (void) +{ + maybe_warn_cpp0x ("variadic templates"); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 0c38a7fcb0c..3e9e612f2b4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1334,10 +1334,10 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, to run a new constructor; and catching an exception, where we have already built up the constructor call so we could wrap it in an exception region. */; - else if (BRACE_ENCLOSED_INITIALIZER_P (init)) + else if (BRACE_ENCLOSED_INITIALIZER_P (init) + && CP_AGGREGATE_TYPE_P (type)) { /* A brace-enclosed initializer for an aggregate. */ - gcc_assert (CP_AGGREGATE_TYPE_P (type)); init = digest_init (type, init); } else diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 290cb7030b5..e42f60afba7 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4639,7 +4639,8 @@ arg_assoc_type (struct arg_lookup *k, tree type) case TYPENAME_TYPE: return false; case LANG_TYPE: - gcc_assert (type == unknown_type_node); + gcc_assert (type == unknown_type_node + || type == init_list_type_node); return false; case TYPE_PACK_EXPANSION: return arg_assoc_type (k, PACK_EXPANSION_PATTERN (type)); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7d530f50714..2323c672166 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -529,6 +529,14 @@ cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword) return cp_lexer_peek_token (lexer)->keyword == keyword; } +/* Return true if the next token is not the indicated KEYWORD. */ + +static inline bool +cp_lexer_next_token_is_not_keyword (cp_lexer* lexer, enum rid keyword) +{ + return cp_lexer_peek_token (lexer)->keyword != keyword; +} + /* Return true if the next token is a keyword for a decl-specifier. */ static bool @@ -1743,6 +1751,8 @@ static tree cp_parser_initializer (cp_parser *, bool *, bool *); static tree cp_parser_initializer_clause (cp_parser *, bool *); +static tree cp_parser_braced_list + (cp_parser*, bool*); static VEC(constructor_elt,gc) *cp_parser_initializer_list (cp_parser *, bool *); @@ -1965,7 +1975,7 @@ static bool cp_parser_optional_template_keyword (cp_parser *); static void cp_parser_pre_parsed_nested_name_specifier (cp_parser *); -static void cp_parser_cache_group +static bool cp_parser_cache_group (cp_parser *, enum cpp_ttype, unsigned); static void cp_parser_parse_tentatively (cp_parser *); @@ -4534,7 +4544,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } /* Form the representation of the compound-literal. */ postfix_expression - = finish_compound_literal (type, initializer_list); + = (finish_compound_literal + (type, build_constructor (init_list_type_node, + initializer_list))); break; } } @@ -5070,10 +5082,19 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, } else { + bool expr_non_constant_p; + /* Parse the next assignment-expression. */ - if (non_constant_p) + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + /* A braced-init-list. */ + maybe_warn_cpp0x ("extended initializer lists"); + expr = cp_parser_braced_list (parser, &expr_non_constant_p); + if (non_constant_p && expr_non_constant_p) + *non_constant_p = true; + } + else if (non_constant_p) { - bool expr_non_constant_p; expr = (cp_parser_constant_expression (parser, /*allow_non_constant_p=*/true, &expr_non_constant_p)); @@ -5535,8 +5556,9 @@ cp_parser_new_expression (cp_parser* parser) else type = cp_parser_new_type_id (parser, &nelts); - /* If the next token is a `(', then we have a new-initializer. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + /* If the next token is a `(' or '{', then we have a new-initializer. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN) + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) initializer = cp_parser_new_initializer (parser); else initializer = NULL_TREE; @@ -5748,6 +5770,7 @@ cp_parser_direct_new_declarator (cp_parser* parser) new-initializer: ( expression-list [opt] ) + braced-init-list Returns a representation of the expression-list. If there is no expression-list, VOID_ZERO_NODE is returned. */ @@ -5757,9 +5780,18 @@ cp_parser_new_initializer (cp_parser* parser) { tree expression_list; - expression_list = (cp_parser_parenthesized_expression_list - (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL)); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_non_constant_p; + maybe_warn_cpp0x ("extended initializer lists"); + expression_list = cp_parser_braced_list (parser, &expr_non_constant_p); + CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; + expression_list = build_tree_list (NULL_TREE, expression_list); + } + else + expression_list = (cp_parser_parenthesized_expression_list + (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL)); if (!expression_list) expression_list = void_zero_node; @@ -6208,10 +6240,14 @@ cp_parser_assignment_expression (cp_parser* parser, bool cast_p) = cp_parser_assignment_operator_opt (parser); if (assignment_operator != ERROR_MARK) { - tree rhs; + bool non_constant_p; /* Parse the right-hand side of the assignment. */ - rhs = cp_parser_assignment_expression (parser, cast_p); + tree rhs = cp_parser_initializer_clause (parser, &non_constant_p); + + if (BRACE_ENCLOSED_INITIALIZER_P (rhs)) + maybe_warn_cpp0x ("extended initializer lists"); + /* An assignment may not appear in a constant-expression. */ if (cp_parser_non_integral_constant_expression (parser, @@ -7124,7 +7160,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p) condition: expression - type-specifier-seq declarator = assignment-expression + type-specifier-seq declarator = initializer-clause + type-specifier-seq declarator braced-init-list GNU Extension: @@ -7170,31 +7207,47 @@ cp_parser_condition (cp_parser* parser) attributes = cp_parser_attributes_opt (parser); /* Parse the asm-specification. */ asm_specification = cp_parser_asm_specification_opt (parser); - /* If the next token is not an `=', then we might still be + /* If the next token is not an `=' or '{', then we might still be looking at an expression. For example: if (A(a).x) looks like a decl-specifier-seq and a declarator -- but then there is no `=', so this is an expression. */ - cp_parser_require (parser, CPP_EQ, "%<=%>"); - /* If we did see an `=', then we are looking at a declaration + if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ) + && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + cp_parser_simulate_error (parser); + + /* If we did see an `=' or '{', then we are looking at a declaration for sure. */ if (cp_parser_parse_definitely (parser)) { tree pushed_scope; bool non_constant_p; + bool flags = LOOKUP_ONLYCONVERTING; /* Create the declaration. */ decl = start_decl (declarator, &type_specifiers, /*initialized_p=*/true, attributes, /*prefix_attributes=*/NULL_TREE, &pushed_scope); - /* Parse the assignment-expression. */ - initializer - = cp_parser_constant_expression (parser, - /*allow_non_constant_p=*/true, - &non_constant_p); + + /* 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; + flags = 0; + } + else + { + /* Consume the `='. */ + cp_lexer_consume_token (parser->lexer); + initializer = cp_parser_initializer_clause (parser, &non_constant_p); + } + if (BRACE_ENCLOSED_INITIALIZER_P (initializer)) + maybe_warn_cpp0x ("extended initializer lists"); + if (!non_constant_p) initializer = fold_non_dependent_expr (initializer); @@ -7202,7 +7255,7 @@ cp_parser_condition (cp_parser* parser) cp_finish_decl (decl, initializer, !non_constant_p, asm_specification, - LOOKUP_ONLYCONVERTING); + flags); if (pushed_scope) pop_scope (pushed_scope); @@ -7426,6 +7479,7 @@ cp_parser_for_init_statement (cp_parser* parser) break ; continue ; return expression [opt] ; + return braced-init-list ; goto identifier ; GNU extension: @@ -7496,12 +7550,18 @@ cp_parser_jump_statement (cp_parser* parser) case RID_RETURN: { tree expr; + bool expr_non_constant_p; - /* If the next token is a `;', then there is no - expression. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + maybe_warn_cpp0x ("extended initializer lists"); + expr = cp_parser_braced_list (parser, &expr_non_constant_p); + } + else if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) expr = cp_parser_expression (parser, /*cast_p=*/false); else + /* If the next token is a `;', then there is no + expression. */ expr = NULL_TREE; /* Build the return-statement. */ statement = finish_return_stmt (expr); @@ -7964,7 +8024,8 @@ cp_parser_simple_declaration (cp_parser* parser, is not a parenthesis, then we must be looking at a declaration. (After "int (" we might be looking at a functional cast.) */ if (decl_specifiers.any_specifiers_p - && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) + && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN) + && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) cp_parser_commit_to_tentative_parse (parser); /* Keep going until we hit the `;' at the end of the simple @@ -8907,6 +8968,7 @@ cp_parser_mem_initializer_list (cp_parser* parser) mem-initializer: mem-initializer-id ( expression-list [opt] ) + mem-initializer-id braced-init-list GNU extension: @@ -8937,11 +8999,20 @@ cp_parser_mem_initializer (cp_parser* parser) if (member && !DECL_P (member)) in_base_initializer = 1; - expression_list - = cp_parser_parenthesized_expression_list (parser, false, - /*cast_p=*/false, - /*allow_expansion_p=*/true, - /*non_constant_p=*/NULL); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_non_constant_p; + maybe_warn_cpp0x ("extended initializer lists"); + expression_list = cp_parser_braced_list (parser, &expr_non_constant_p); + CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; + expression_list = build_tree_list (NULL_TREE, expression_list); + } + else + expression_list + = cp_parser_parenthesized_expression_list (parser, false, + /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL); if (expression_list == error_mark_node) return error_mark_node; if (!expression_list) @@ -12197,7 +12268,7 @@ cp_parser_init_declarator (cp_parser* parser, initialized with "= ..", CPP_OPEN_PAREN if initialized with "(...)". */ enum cpp_ttype initialization_kind; - bool is_parenthesized_init = false; + bool is_direct_init = false; bool is_non_constant_init; int ctor_dtor_or_conv_p; bool friend_p; @@ -12263,7 +12334,8 @@ cp_parser_init_declarator (cp_parser* parser, token = cp_lexer_peek_token (parser->lexer); /* Check to see if the token indicates the start of a function-definition. */ - if (cp_parser_token_starts_function_definition_p (token)) + if (function_declarator_p (declarator) + && cp_parser_token_starts_function_definition_p (token)) { if (!function_definition_allowed_p) { @@ -12314,9 +12386,10 @@ cp_parser_init_declarator (cp_parser* parser, return error_mark_node; } - /* An `=' or an `(' indicates an initializer. */ + /* An `=' or an `(', or an '{' in C++0x, indicates an initializer. */ if (token->type == CPP_EQ - || token->type == CPP_OPEN_PAREN) + || token->type == CPP_OPEN_PAREN + || token->type == CPP_OPEN_BRACE) { is_initialized = true; initialization_kind = token->type; @@ -12399,7 +12472,7 @@ cp_parser_init_declarator (cp_parser* parser, /* Parse the initializer. */ initializer = NULL_TREE; - is_parenthesized_init = false; + is_direct_init = false; is_non_constant_init = true; if (is_initialized) { @@ -12422,7 +12495,7 @@ cp_parser_init_declarator (cp_parser* parser, } else initializer = cp_parser_initializer (parser, - &is_parenthesized_init, + &is_direct_init, &is_non_constant_init); } @@ -12430,7 +12503,8 @@ cp_parser_init_declarator (cp_parser* parser, initializer. Mark Mitchell proposed removing this functionality on the GCC mailing lists on 2002-08-13. This parser accepts the attributes -- but ignores them. */ - if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init) + if (cp_parser_allow_gnu_extensions_p (parser) + && initialization_kind == CPP_OPEN_PAREN) if (cp_parser_attributes_opt (parser)) warning (OPT_Wattributes, "attributes after parenthesized initializer ignored"); @@ -12463,8 +12537,8 @@ cp_parser_init_declarator (cp_parser* parser, a direct-initialization, which means that an `explicit' constructor is OK. Otherwise, an `explicit' constructor cannot be used. */ - ((is_parenthesized_init || !is_initialized) - ? 0 : LOOKUP_ONLYCONVERTING)); + ((is_direct_init || !is_initialized) + ? 0 : LOOKUP_ONLYCONVERTING)); } else if ((cxx_dialect != cxx98) && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL) @@ -13983,14 +14057,14 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser) Returns an expression representing the initializer. If no initializer is present, NULL_TREE is returned. - *IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )' - production is used, and zero otherwise. *IS_PARENTHESIZED_INIT is - set to FALSE if there is no initializer present. If there is an + *IS_DIRECT_INIT is set to FALSE if the `= initializer-clause' + production is used, and TRUE otherwise. *IS_DIRECT_INIT is + set to TRUE if there is no initializer present. If there is an initializer, and it is not a constant-expression, *NON_CONSTANT_P is set to true; otherwise it is set to false. */ static tree -cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, +cp_parser_initializer (cp_parser* parser, bool* is_direct_init, bool* non_constant_p) { cp_token *token; @@ -14001,7 +14075,7 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, /* Let our caller know whether or not this initializer was parenthesized. */ - *is_parenthesized_init = (token->type == CPP_OPEN_PAREN); + *is_direct_init = (token->type != CPP_EQ); /* Assume that the initializer is constant. */ *non_constant_p = false; @@ -14017,6 +14091,12 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, /*cast_p=*/false, /*allow_expansion_p=*/true, non_constant_p); + else if (token->type == CPP_OPEN_BRACE) + { + maybe_warn_cpp0x ("extended initializer lists"); + init = cp_parser_braced_list (parser, non_constant_p); + CONSTRUCTOR_IS_DIRECT_INIT (init) = 1; + } else { /* Anything else is an error. */ @@ -14031,20 +14111,14 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, initializer-clause: assignment-expression - { initializer-list , [opt] } - { } + braced-init-list Returns an expression representing the initializer. If the `assignment-expression' production is used the value returned is simply a representation for the expression. - Otherwise, a CONSTRUCTOR is returned. The CONSTRUCTOR_ELTS will be - the elements of the initializer-list (or NULL, if the last - production is used). The TREE_TYPE for the CONSTRUCTOR will be - NULL_TREE. There is no way to detect whether or not the optional - trailing `,' was provided. NON_CONSTANT_P is as for - cp_parser_initializer. */ + Otherwise, calls cp_parser_braced_list. */ static tree cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) @@ -14066,25 +14140,46 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) initializer = fold_non_dependent_expr (initializer); } else + initializer = cp_parser_braced_list (parser, non_constant_p); + + return initializer; +} + +/* Parse a brace-enclosed initializer list. + + braced-init-list: + { initializer-list , [opt] } + { } + + Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be + the elements of the initializer-list (or NULL, if the last + production is used). The TREE_TYPE for the CONSTRUCTOR will be + NULL_TREE. There is no way to detect whether or not the optional + trailing `,' was provided. NON_CONSTANT_P is as for + cp_parser_initializer. */ + +static tree +cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) +{ + tree initializer; + + /* Consume the `{' token. */ + cp_lexer_consume_token (parser->lexer); + /* Create a CONSTRUCTOR to represent the braced-initializer. */ + initializer = make_node (CONSTRUCTOR); + /* If it's not a `}', then there is a non-trivial initializer. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)) { - /* Consume the `{' token. */ - cp_lexer_consume_token (parser->lexer); - /* Create a CONSTRUCTOR to represent the braced-initializer. */ - initializer = make_node (CONSTRUCTOR); - /* If it's not a `}', then there is a non-trivial initializer. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE)) - { - /* Parse the initializer list. */ - CONSTRUCTOR_ELTS (initializer) - = cp_parser_initializer_list (parser, non_constant_p); - /* A trailing `,' token is allowed. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) - cp_lexer_consume_token (parser->lexer); - } - /* Now, there should be a trailing `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); + /* Parse the initializer list. */ + CONSTRUCTOR_ELTS (initializer) + = cp_parser_initializer_list (parser, non_constant_p); + /* A trailing `,' token is allowed. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); } - + /* Now, there should be a trailing `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); + TREE_TYPE (initializer) = init_list_type_node; return initializer; } @@ -17297,11 +17392,22 @@ cp_parser_functional_cast (cp_parser* parser, tree type) { tree expression_list; tree cast; + bool nonconst_p; + + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + maybe_warn_cpp0x ("extended initializer lists"); + expression_list = cp_parser_braced_list (parser, &nonconst_p); + CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1; + if (TREE_CODE (type) == TYPE_DECL) + type = TREE_TYPE (type); + return finish_compound_literal (type, expression_list); + } expression_list = cp_parser_parenthesized_expression_list (parser, false, /*cast_p=*/true, - /*allow_expansion_p=*/true, + /*allow_expansion_p=*/true, /*non_constant_p=*/NULL); cast = build_functional_cast (type, expression_list, @@ -17352,6 +17458,22 @@ cp_parser_save_member_function_body (cp_parser* parser, /* Save away the tokens that make up the body of the function. */ first = parser->lexer->next_token; + /* We can have braced-init-list mem-initializers before the fn body. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + cp_lexer_consume_token (parser->lexer); + while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) + && cp_lexer_next_token_is_not_keyword (parser->lexer, RID_TRY)) + { + /* cache_group will stop after an un-nested { } pair, too. */ + if (cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0)) + break; + + /* variadic mem-inits have ... after the ')'. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + cp_lexer_consume_token (parser->lexer); + } + } cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0); /* Handle function try blocks. */ while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH)) @@ -18210,41 +18332,54 @@ cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser) parser->object_scope = NULL_TREE; } -/* Consume tokens up through a non-nested END token. */ +/* Consume tokens up through a non-nested END token. Returns TRUE if we + encounter the end of a block before what we were looking for. */ -static void +static bool cp_parser_cache_group (cp_parser *parser, enum cpp_ttype end, unsigned depth) { while (true) { - cp_token *token; + cp_token *token = cp_lexer_peek_token (parser->lexer); - /* Abort a parenthesized expression if we encounter a brace. */ + /* Abort a parenthesized expression if we encounter a semicolon. */ if ((end == CPP_CLOSE_PAREN || depth == 0) - && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) - return; + && token->type == CPP_SEMICOLON) + return true; /* If we've reached the end of the file, stop. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_EOF) + if (token->type == CPP_EOF || (end != CPP_PRAGMA_EOL - && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL))) - return; - /* Consume the next token. */ - token = cp_lexer_consume_token (parser->lexer); + && token->type == CPP_PRAGMA_EOL)) + return true; + if (token->type == CPP_CLOSE_BRACE && depth == 0) + /* We've hit the end of an enclosing block, so there's been some + kind of syntax error. */ + return true; + + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); /* See if it starts a new group. */ if (token->type == CPP_OPEN_BRACE) { cp_parser_cache_group (parser, CPP_CLOSE_BRACE, depth + 1); + /* In theory this should probably check end == '}', but + cp_parser_save_member_function_body needs it to exit + after either '}' or ')' when called with ')'. */ if (depth == 0) - return; + return false; } else if (token->type == CPP_OPEN_PAREN) - cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1); + { + cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1); + if (depth == 0 && end == CPP_CLOSE_PAREN) + return false; + } else if (token->type == CPP_PRAGMA) cp_parser_cache_group (parser, CPP_PRAGMA_EOL, depth + 1); else if (token->type == end) - return; + return false; } } @@ -20503,10 +20638,10 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) if (CLASS_TYPE_P (TREE_TYPE (decl)) || type_dependent_expression_p (decl)) { - bool is_parenthesized_init, is_non_constant_init; + bool is_direct_init, is_non_constant_init; init = cp_parser_initializer (parser, - &is_parenthesized_init, + &is_direct_init, &is_non_constant_init); cp_finish_decl (decl, init, !is_non_constant_init, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f24b6ff04b3..cce706f0705 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11507,6 +11507,7 @@ tsubst_copy_and_build (tree t, bool process_index_p; int newlen; bool need_copy_p = false; + tree r; if (type == error_mark_node) return error_mark_node; @@ -11571,10 +11572,12 @@ tsubst_copy_and_build (tree t, } } + r = build_constructor (init_list_type_node, n); + if (TREE_HAS_CONSTRUCTOR (t)) - return finish_compound_literal (type, n); + return finish_compound_literal (type, r); - return build_constructor (NULL_TREE, n); + return r; } case TYPEID_EXPR: @@ -12271,6 +12274,8 @@ type_unification_real (tree tparms, arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg, arg_expr); + if (arg == init_list_type_node && arg_expr) + arg = arg_expr; if (unify (tparms, targs, parm, arg, arg_strict)) return 1; } @@ -13037,7 +13042,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) if (arg == error_mark_node) return 1; - if (arg == unknown_type_node) + if (arg == unknown_type_node + || arg == init_list_type_node) /* We can't deduce anything from this, but we might get all the template args from other function args. */ return 0; @@ -13049,6 +13055,31 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) if (arg == parm && !uses_template_parms (parm)) return 0; + /* Handle init lists early, so the rest of the function can assume + we're dealing with a type. */ + if (BRACE_ENCLOSED_INITIALIZER_P (arg)) + { + tree elt, elttype; + unsigned i; + + if (!is_std_init_list (parm)) + /* We can only deduce from an initializer list argument if the + parameter is std::initializer_list; otherwise this is a + non-deduced context. */ + return 0; + + elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0); + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (arg), i, elt) + { + if (!BRACE_ENCLOSED_INITIALIZER_P (elt)) + elt = TREE_TYPE (elt); + if (unify (tparms, targs, elttype, elt, UNIFY_ALLOW_NONE)) + return 1; + } + return 0; + } + /* Immediately reject some pairs that won't unify because of cv-qualification mismatches. */ if (TREE_CODE (arg) == TREE_CODE (parm) diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 1dcd785371a..8a36f0b77b7 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -900,7 +900,7 @@ tinfo_base_init (tinfo_s *ti, tree target) init = tree_cons (NULL_TREE, decay_conversion (name_decl), init); - init = build_constructor_from_list (NULL_TREE, nreverse (init)); + init = build_constructor_from_list (init_list_type_node, nreverse (init)); TREE_CONSTANT (init) = 1; TREE_STATIC (init) = 1; init = tree_cons (NULL_TREE, init, NULL_TREE); @@ -917,7 +917,7 @@ generic_initializer (tinfo_s *ti, tree target) { tree init = tinfo_base_init (ti, target); - init = build_constructor_from_list (NULL_TREE, init); + init = build_constructor_from_list (init_list_type_node, init); TREE_CONSTANT (init) = 1; TREE_STATIC (init) = 1; return init; @@ -942,7 +942,7 @@ ptr_initializer (tinfo_s *ti, tree target) get_tinfo_ptr (TYPE_MAIN_VARIANT (to)), init); - init = build_constructor_from_list (NULL_TREE, nreverse (init)); + init = build_constructor_from_list (init_list_type_node, nreverse (init)); TREE_CONSTANT (init) = 1; TREE_STATIC (init) = 1; return init; @@ -974,7 +974,7 @@ ptm_initializer (tinfo_s *ti, tree target) get_tinfo_ptr (klass), init); - init = build_constructor_from_list (NULL_TREE, nreverse (init)); + init = build_constructor_from_list (init_list_type_node, nreverse (init)); TREE_CONSTANT (init) = 1; TREE_STATIC (init) = 1; return init; @@ -990,7 +990,7 @@ class_initializer (tinfo_s *ti, tree target, tree trail) tree init = tinfo_base_init (ti, target); TREE_CHAIN (init) = trail; - init = build_constructor_from_list (NULL_TREE, init); + init = build_constructor_from_list (init_list_type_node, init); TREE_CONSTANT (init) = 1; TREE_STATIC (init) = 1; return init; @@ -1102,10 +1102,10 @@ get_pseudo_ti_init (tree type, unsigned tk_index) build_int_cst (offset_type, flags)); base_init = tree_cons (NULL_TREE, offset, base_init); base_init = tree_cons (NULL_TREE, tinfo, base_init); - base_init = build_constructor_from_list (NULL_TREE, base_init); + base_init = build_constructor_from_list (init_list_type_node, base_init); base_inits = tree_cons (NULL_TREE, base_init, base_inits); } - base_inits = build_constructor_from_list (NULL_TREE, base_inits); + base_inits = build_constructor_from_list (init_list_type_node, base_inits); base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE); /* Prepend the number of bases. */ base_inits = tree_cons (NULL_TREE, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2400aeb37da..fa65e9b2804 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2099,21 +2099,17 @@ finish_unary_op_expr (enum tree_code code, tree expr) } /* Finish a compound-literal expression. TYPE is the type to which - the INITIALIZER_LIST is being cast. */ + the CONSTRUCTOR in COMPOUND_LITERAL is being cast. */ tree -finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list) +finish_compound_literal (tree type, tree compound_literal) { - tree compound_literal; - if (!TYPE_OBJ_P (type)) { error ("compound literal of non-object type %qT", type); return error_mark_node; } - /* Build a CONSTRUCTOR for the INITIALIZER_LIST. */ - compound_literal = build_constructor (NULL_TREE, initializer_list); if (processing_template_decl) { TREE_TYPE (compound_literal) = type; @@ -2123,6 +2119,18 @@ finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list) } type = complete_type (type); + + if (TYPE_NON_AGGREGATE_CLASS (type)) + { + /* Trying to deal with a CONSTRUCTOR instead of a TREE_LIST + everywhere that deals with function arguments would be a pain, so + just wrap it in a TREE_LIST. The parser set a flag so we know + that it came from T{} rather than T({}). */ + CONSTRUCTOR_IS_DIRECT_INIT (compound_literal) = 1; + compound_literal = build_tree_list (NULL_TREE, compound_literal); + return build_functional_cast (type, compound_literal, tf_error); + } + if (TREE_CODE (type) == ARRAY_TYPE && check_array_initializer (NULL_TREE, type, compound_literal)) return error_mark_node; @@ -2130,7 +2138,19 @@ finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list) if (TREE_CODE (type) == ARRAY_TYPE) cp_complete_array_type (&type, compound_literal, false); compound_literal = digest_init (type, compound_literal); - return get_target_expr (compound_literal); + if ((!at_function_scope_p () || cp_type_readonly (type)) + && initializer_constant_valid_p (compound_literal, type)) + { + tree decl = create_temporary_var (type); + DECL_INITIAL (decl) = compound_literal; + TREE_STATIC (decl) = 1; + decl = pushdecl_top_level (decl); + DECL_NAME (decl) = make_anon_name (); + SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl)); + return decl; + } + else + return get_target_expr (compound_literal); } /* Return the declaration for the function-name variable indicated by diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index ff372206ee6..b7c0a8d33b8 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -616,6 +616,14 @@ build_cplus_array_type (tree elt_type, tree index_type) return t; } +/* Return an ARRAY_TYPE with element type ELT and length N. */ + +tree +build_array_of_n_type (tree elt, int n) +{ + return build_cplus_array_type (elt, build_index_type (size_int (n - 1))); +} + /* Return a reference type node referring to TO_TYPE. If RVAL is true, return an rvalue reference type, otherwise return an lvalue reference type. If a type node exists, reuse it, otherwise create diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 05e88b9002e..4cf8021964f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "output.h" #include "diagnostic.h" +#include "real.h" static tree process_init_constructor (tree type, tree init); @@ -592,7 +593,7 @@ store_init_value (tree decl, tree init) { error ("constructor syntax used, but no constructor declared " "for type %qT", type); - init = build_constructor_from_list (NULL_TREE, nreverse (init)); + init = build_constructor_from_list (init_list_type_node, nreverse (init)); } } else if (TREE_CODE (init) == TREE_LIST @@ -631,15 +632,70 @@ store_init_value (tree decl, tree init) } +/* Give errors about narrowing conversions within { }. */ + +void +check_narrowing (tree type, tree init) +{ + tree ftype = TREE_TYPE (init); + bool ok = true; + REAL_VALUE_TYPE d; + + if (DECL_P (init)) + init = decl_constant_value (init); + + if (TREE_CODE (type) == INTEGER_TYPE + && TREE_CODE (ftype) == REAL_TYPE) + ok = false; + else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype) + && CP_INTEGRAL_TYPE_P (type)) + { + if (TYPE_PRECISION (type) < TYPE_PRECISION (ftype) + && (TREE_CODE (init) != INTEGER_CST + || !int_fits_type_p (init, type))) + ok = false; + } + else if (TREE_CODE (ftype) == REAL_TYPE + && TREE_CODE (type) == REAL_TYPE) + { + if (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)) + { + ok = false; + if (TREE_CODE (init) == REAL_CST) + { + d = TREE_REAL_CST (init); + if (exact_real_truncate (TYPE_MODE (type), &d)) + ok = true; + } + } + } + else if (INTEGRAL_OR_ENUMERATION_TYPE_P (ftype) + && TREE_CODE (type) == REAL_TYPE) + { + ok = false; + if (TREE_CODE (init) == INTEGER_CST) + { + d = real_value_from_int_cst (0, init); + if (exact_real_truncate (TYPE_MODE (type), &d)) + ok = true; + } + } + + if (!ok) + error ("narrowing conversion of %qE to %qT inside { }", init, type); +} + /* Process the initializer INIT for a variable of type TYPE, emitting diagnostics for invalid initializers and converting the initializer as appropriate. For aggregate types, it assumes that reshape_init has already run, thus the - initializer will have the right shape (brace elision has been undone). */ + initializer will have the right shape (brace elision has been undone). -tree -digest_init (tree type, tree init) + NESTED is true iff we are being called for an element of a CONSTRUCTOR. */ + +static tree +digest_init_r (tree type, tree init, bool nested) { enum tree_code code = TREE_CODE (type); @@ -706,6 +762,8 @@ digest_init (tree type, tree init) { tree *exp; + if (cxx_dialect != cxx98 && nested) + check_narrowing (type, init); init = convert_for_initialization (0, type, init, LOOKUP_NORMAL, "initialization", NULL_TREE, 0, tf_warning_or_error); @@ -731,7 +789,7 @@ digest_init (tree type, tree init) || TREE_CODE (type) == COMPLEX_TYPE); if (BRACE_ENCLOSED_INITIALIZER_P (init)) - return process_init_constructor (type, init); + return process_init_constructor (type, init); else { if (COMPOUND_LITERAL_P (init) && TREE_CODE (type) == ARRAY_TYPE) @@ -757,6 +815,11 @@ digest_init (tree type, tree init) } } +tree +digest_init (tree type, tree init) +{ + return digest_init_r (type, init, false); +} /* Set of flags used within process_init_constructor to describe the initializers. */ @@ -828,7 +891,7 @@ process_init_constructor_array (tree type, tree init) else ce->index = size_int (i); gcc_assert (ce->value); - ce->value = digest_init (TREE_TYPE (type), ce->value); + ce->value = digest_init_r (TREE_TYPE (type), ce->value, true); if (ce->value != error_mark_node) gcc_assert (same_type_ignoring_top_level_qualifiers_p @@ -854,7 +917,7 @@ process_init_constructor_array (tree type, tree init) next = build_functional_cast (TREE_TYPE (type), NULL_TREE, tf_warning_or_error); else - next = build_constructor (NULL_TREE, NULL); + next = build_constructor (init_list_type_node, NULL); next = digest_init (TREE_TYPE (type), next); } else if (!zero_init_p (TREE_TYPE (type))) @@ -929,7 +992,7 @@ process_init_constructor_record (tree type, tree init) } gcc_assert (ce->value); - next = digest_init (TREE_TYPE (field), ce->value); + next = digest_init_r (TREE_TYPE (field), ce->value, true); ++idx; } else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field))) @@ -942,9 +1005,9 @@ process_init_constructor_record (tree type, tree init) next = build_functional_cast (TREE_TYPE (field), NULL_TREE, tf_warning_or_error); else - next = build_constructor (NULL_TREE, NULL); + next = build_constructor (init_list_type_node, NULL); - next = digest_init (TREE_TYPE (field), next); + next = digest_init_r (TREE_TYPE (field), next, true); /* Warn when some struct elements are implicitly initialized. */ warning (OPT_Wmissing_field_initializers, @@ -1037,7 +1100,7 @@ process_init_constructor_union (tree type, tree init) } if (ce->value && ce->value != error_mark_node) - ce->value = digest_init (TREE_TYPE (ce->index), ce->value); + ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true); return picflag_from_initializer (ce->value); } diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist1.C b/gcc/testsuite/g++.dg/cpp0x/initlist1.C new file mode 100644 index 00000000000..b7583da7829 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist1.C @@ -0,0 +1,69 @@ +// Basic uses of initializer lists +// { dg-do run } +// { dg-options "-std=c++0x" } + +#include + +extern "C" void abort(); + +using namespace std; + +struct A { int i,j; A(int _i,int _j): i(_i), j(_j) {} }; +struct B { A a; B(A _a): a(_a) {} }; +struct C { B b; C(B _b): b(_b) {} }; + +struct D +{ + int ia[3]; + D (initializer_list l) + { + const int *p = l.begin(); + for (int i = 0; i < 3; ++i) + ia[i] = *p++; + } +}; + +void f(C c) +{ + if (c.b.a.i != 1) abort(); + if (c.b.a.j != 2) abort(); +} +void f(int); + +void g(D d) +{ + if (d.ia[0] != 1 || d.ia[1] != 2 || d.ia[2] != 3) + abort(); +} + +struct E +{ + int i, j, k; +}; + +void h(E e) +{ + if (e.i != 1 || e.j != 2 || e.k != 3) + abort(); +} + +void i(initializer_list l) +{ + const int *p = l.begin(); + if (*p++ != 1) abort(); + if (*p++ != 2) abort(); + if (*p++ != 3) abort(); + if (p != l.end()) abort(); +} + +int main() +{ + g({1,2,3}); + + h({1,2,3}); + + f({{{1,2}}}); + f({{A{1,2}}}); + + i({1,2,3}); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist2.C b/gcc/testsuite/g++.dg/cpp0x/initlist2.C new file mode 100644 index 00000000000..2fe4770560d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist2.C @@ -0,0 +1,32 @@ +// Test that conversion to std::initializer_list takes priority over other +// user-defined conversions. + +// { dg-do link } +// { dg-options "-std=c++0x" } + +#include + +struct string +{ + string (const char *) {} + template string (Iter, Iter); +}; + +template +struct pair +{ + pair (T t, U u) {} +}; + +template +struct map +{ + void insert (pair); + void insert (std::initializer_list >) {} +}; + +int main() +{ + map m; + m.insert({ {"this","that"}, {"me","you"} }); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist3.C b/gcc/testsuite/g++.dg/cpp0x/initlist3.C new file mode 100644 index 00000000000..412deb51129 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist3.C @@ -0,0 +1,11 @@ +// { dg-options "-std=c++0x" } + +#include + +template void f(std::initializer_list); + +void g() +{ + f({1,2,3}); +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist4.C b/gcc/testsuite/g++.dg/cpp0x/initlist4.C new file mode 100644 index 00000000000..d1ffab8546c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist4.C @@ -0,0 +1,32 @@ +// Test for initializer-list 'explicit' rule +// { dg-options "-std=c++0x" } + +struct A +{ + explicit A(int,int); + operator bool(); +}; + +A f(A) +{ + A{1,2}; + A a1{1,2}; + new A{1,2}; + if (A a5{1,2}); + + A({1,2}); // { dg-error "explicit" } + A a2({1,2}); // { dg-error "explicit" } + A a3 = {1,2}; // { dg-error "explicit" } + new A({1,2}); // { dg-error "explicit" } + f({1,2}); // { dg-error "explicit" } + a1 = {1,2}; // { dg-error "explicit" } + if (A a4 = {1,2}); // { dg-error "explicit" } + return {1,2}; // { dg-error "explicit" } +} + +struct B +{ + A a; + B(): a{1,2} {} + B(const B&): a({1,2}) {} // { dg-error "explicit" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist5.C b/gcc/testsuite/g++.dg/cpp0x/initlist5.C new file mode 100644 index 00000000000..0d02fd42d7f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist5.C @@ -0,0 +1,21 @@ +// Test for narrowing diagnostics +// { dg-options "-std=c++0x" } + +#include + +struct A { int i; int j; }; +A a2 { 1.2 }; // { dg-error "narrowing" } +A a1 { 1, 2 }; // aggregate initialization +struct B { + B(std::initializer_list); +}; +B b1 { 1, 2 }; // creates initializer_list and calls constructor +B b2 { 1, 2.0 }; // { dg-error "narrowing" } +struct C { + C(int i, double j); +}; +C c1 = { 1, 2.2 }; // calls constructor with arguments (1, 2.2) +C c2 = { 1.1, 2 }; // { dg-error "narrowing" } + +int j { 1 }; // initialize to 1 +int k {}; // initialize to 0 diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist6.C b/gcc/testsuite/g++.dg/cpp0x/initlist6.C new file mode 100644 index 00000000000..523570315eb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist6.C @@ -0,0 +1,30 @@ +// Test for initlist lifetime +// { dg-options "-std=c++0x" } +// { dg-do run } + +#include + +int c; + +struct A +{ + A(int,int) { ++c; } + ~A() { --c; } +}; + +void f (std::initializer_list l) { } + +int main() +{ + f({ {1,2}, {3,4} }); + if (c != 0) + return 1; + + { + std::initializer_list l { {1,2}, {3,4} }; + if (c != 2) + return 2; + } + if (c != 0) + return 3; +} diff --git a/gcc/testsuite/g++.dg/inherit/error4.C b/gcc/testsuite/g++.dg/inherit/error4.C index 77fa75d1994..d56d67f7556 100644 --- a/gcc/testsuite/g++.dg/inherit/error4.C +++ b/gcc/testsuite/g++.dg/inherit/error4.C @@ -2,9 +2,9 @@ struct A { virtual ~A(); }; -struct B : A A {}; // { dg-error "'A'|function definition|extra" } +struct B : A A {}; // { dg-error "" } -A foo(const B &b) +A foo(const B &b) // { dg-error "" } { - return b; // { dg-error "conversion" } + return b; } diff --git a/gcc/testsuite/g++.dg/init/brace2.C b/gcc/testsuite/g++.dg/init/brace2.C index 2af063d5f56..619a20f3c70 100644 --- a/gcc/testsuite/g++.dg/init/brace2.C +++ b/gcc/testsuite/g++.dg/init/brace2.C @@ -5,4 +5,4 @@ const char * y = { "hello" }; int a = 2; int b = { 2,3 }; // { dg-error "requires one element in initializer" } int c = { { 2 } } ; // { dg-error "braces around scalar initializer" } -int d = {}; // { dg-error "requires one element in initializer" } +int d = {}; // { dg-error "initializer" } diff --git a/gcc/testsuite/g++.dg/init/brace6.C b/gcc/testsuite/g++.dg/init/brace6.C index ffb70118f9e..066d1ba65ff 100644 --- a/gcc/testsuite/g++.dg/init/brace6.C +++ b/gcc/testsuite/g++.dg/init/brace6.C @@ -6,7 +6,7 @@ struct A { }; struct B { - B(const B&); + B(const B&); // { dg-error "candidate" } int b; }; @@ -18,8 +18,8 @@ int main() { int i = { 1 }; int j = { 1, 2 }; /* { dg-error "requires one element" } */ - A a = { 6 }; /* { dg-error "initializer for non" } */ - B b = { 6 }; /* { dg-error "initializer for non" } */ + A a = { 6 }; /* { dg-error "initialize" } */ + B b = { 6 }; /* { dg-error "initialize" } */ C c = { 6 }; /* { dg-error "too many initializers" } */ D d = { 6 }; } diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C index bcd96e4ec1f..1397e87d256 100644 --- a/gcc/testsuite/g++.dg/parse/crash36.C +++ b/gcc/testsuite/g++.dg/parse/crash36.C @@ -2,7 +2,7 @@ // { dg-do compile } // { dg-options "-std=c++98" } -template struct A // { dg-error "does not include variadic templates" } +template struct A // { dg-error "variadic templates" } { static T &t; // { dg-error "not expanded with|T" } static const int i = sizeof (++t); // { dg-error "was not declared in this scope" } diff --git a/gcc/testsuite/g++.dg/parse/ctor3.C b/gcc/testsuite/g++.dg/parse/ctor3.C index 193ffae24fe..e597d926f40 100644 --- a/gcc/testsuite/g++.dg/parse/ctor3.C +++ b/gcc/testsuite/g++.dg/parse/ctor3.C @@ -4,5 +4,5 @@ struct A {}; struct B : A { - B() : A {} // { dg-error "expected" } + B() : A {} // { dg-error "initializer|expected" } }; diff --git a/gcc/tree.c b/gcc/tree.c index d9e4e7f18db..a8f66dbb895 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1827,6 +1827,26 @@ tree_cons_stat (tree purpose, tree value, tree chain MEM_STAT_DECL) return node; } +/* Return the elements of a CONSTRUCTOR as a TREE_LIST. */ + +tree +ctor_to_list (tree ctor) +{ + tree list = NULL_TREE; + tree *p = &list; + unsigned ix; + constructor_elt *ce; + + for (ix = 0; + VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (ctor), ix, ce); + ++ix) + { + *p = build_tree_list (ce->index, ce->value); + p = &TREE_CHAIN (*p); + } + + return list; +} /* Return the size nominally occupied by an object of type TYPE when it resides in memory. The value is measured in units of bytes, diff --git a/gcc/tree.h b/gcc/tree.h index c00ad54cf05..e6b9f9cf65e 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1586,6 +1586,9 @@ struct tree_vec GTY(()) /* In a CONSTRUCTOR node. */ #define CONSTRUCTOR_ELTS(NODE) (CONSTRUCTOR_CHECK (NODE)->constructor.elts) +#define CONSTRUCTOR_ELT(NODE,IDX) \ + (VEC_index (constructor_elt, CONSTRUCTOR_ELTS (NODE), IDX)) +#define CONSTRUCTOR_NELTS(NODE) (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (NODE))) /* Iterate through the vector V of CONSTRUCTOR_ELT elements, yielding the value of each element (stored within VAL). IX must be a scratch variable @@ -4475,6 +4478,10 @@ extern int fields_length (const_tree); extern bool initializer_zerop (const_tree); +/* Given a CONSTRUCTOR CTOR, return the elements as a TREE_LIST. */ + +extern tree ctor_to_list (tree); + /* Examine CTOR to discover: * how many scalar fields are set to nonzero values, and place it in *P_NZ_ELTS; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 42a56a22a93..4c3689e3421 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2008-07-02 Jason Merrill + + * libsupc++/initializer_list: New file. + * include/bits/stl_map.h (insert(initializer_list)): New method. + 2008-06-30 Alfred E. Heggestad * include/backward/backward_warning.h: Fix typo. diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index a9486708ffe..cf0c16bc42d 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -64,6 +64,7 @@ #include #include +#include _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D) @@ -468,6 +469,18 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D) insert(const value_type& __x) { return _M_t._M_insert_unique(__x); } + /** + * @brief Attempts to insert a list of std::pairs into the %map. + * @param list A std::initializer_list of pairs to be + * inserted. + * + * Complexity similar to that of the range constructor. + * + */ + void + insert(std::initializer_list list) + { insert (list.begin(), list.end()); } + /** * @brief Attempts to insert a std::pair into the %map. * @param position An iterator that serves as a hint as to where the diff --git a/libstdc++-v3/libsupc++/initializer_list b/libstdc++-v3/libsupc++/initializer_list new file mode 100644 index 00000000000..1a3cba3dd02 --- /dev/null +++ b/libstdc++-v3/libsupc++/initializer_list @@ -0,0 +1,64 @@ +// std::initializer_list support -*- C++ -*- + +// Copyright (C) 2008 Free Software Foundation, Inc. +// +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301, USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#ifndef __CXX_INITIALIZER_LIST +#define __CXX_INITIALIZER_LIST + +#pragma GCC visibility push(default) + +#include + +namespace std +{ + template + class initializer_list + { + const E* _array; + size_t _len; + + // The compiler can call a private constructor. + initializer_list(const E* _a, size_t _l) + : _array(_a), _len(_l) { } + + public: + initializer_list() + : _array(NULL), _len(0) {} + + size_t size() const // number of elements + { return _len; } + const E* begin() const // first element + { return _array; } + const E* end() const // one past the last element + { return begin() + size(); } + }; +} + +#pragma GCC visibility pop +#endif // __CXX_INITIALIZER_LIST -- 2.30.2