Implement WG21 N2672, Initializer List proposed wording
gcc/cp/ChangeLog: 2008-07-02 Jason Merrill <jason@redhat.com> 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 <jason@redhat.com> * 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 <jason@redhat.com> * libsupc++/initializer_list: New file. * include/bits/stl_map.h (insert(initializer_list)): New method. From-SVN: r137361
This commit is contained in:
parent
906c5773db
commit
0935784671
31 changed files with 1214 additions and 276 deletions
|
@ -1,3 +1,10 @@
|
|||
2008-07-02 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* tree.c (ctor_to_list): New fn.
|
||||
* tree.h: Declare it.
|
||||
(CONSTRUCTOR_ELT): New macro.
|
||||
(CONSTRUCTOR_NELTS): New macro.
|
||||
|
||||
2008-07-02 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* tree-ssa-structalias.c (struct variable_info): Reorder
|
||||
|
|
|
@ -1,3 +1,73 @@
|
|||
2008-07-02 Jason Merrill <jason@redhat.com>
|
||||
|
||||
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 <dan@codesourcery.com>
|
||||
|
||||
* typeck.c (comp_ptr_ttypes_real): Use vector_targets_convertible_p.
|
||||
|
|
368
gcc/cp/call.c
368
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<T>, 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<T>. */
|
||||
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<T>. */
|
||||
|
||||
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"
|
||||
|
|
|
@ -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<T>) 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);
|
||||
|
|
|
@ -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]). */
|
||||
|
|
173
gcc/cp/decl.c
173
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<T> 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)
|
||||
{
|
||||
|
|
|
@ -284,7 +284,10 @@ dump_type (tree t, int flags)
|
|||
switch (TREE_CODE (t))
|
||||
{
|
||||
case UNKNOWN_TYPE:
|
||||
pp_identifier (cxx_pp, "<unresolved overloaded function type>");
|
||||
if (t == init_list_type_node)
|
||||
pp_identifier (cxx_pp, "<brace-enclosed initializer list>");
|
||||
else
|
||||
pp_identifier (cxx_pp, "<unresolved overloaded function type>");
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
309
gcc/cp/parser.c
309
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,28 +14140,49 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
|
|||
initializer = fold_non_dependent_expr (initializer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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, "%<}%>");
|
||||
}
|
||||
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))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Parse an initializer-list.
|
||||
|
||||
initializer-list:
|
||||
|
@ -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,
|
||||
|
|
39
gcc/cp/pt.c
39
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,
|
|||
}
|
||||
}
|
||||
|
||||
if (TREE_HAS_CONSTRUCTOR (t))
|
||||
return finish_compound_literal (type, n);
|
||||
r = build_constructor (init_list_type_node, n);
|
||||
|
||||
return build_constructor (NULL_TREE, n);
|
||||
if (TREE_HAS_CONSTRUCTOR (t))
|
||||
return finish_compound_literal (type, r);
|
||||
|
||||
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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
69
gcc/testsuite/g++.dg/cpp0x/initlist1.C
Normal file
69
gcc/testsuite/g++.dg/cpp0x/initlist1.C
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Basic uses of initializer lists
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
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<int> 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<int> 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});
|
||||
}
|
32
gcc/testsuite/g++.dg/cpp0x/initlist2.C
Normal file
32
gcc/testsuite/g++.dg/cpp0x/initlist2.C
Normal file
|
@ -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 <initializer_list>
|
||||
|
||||
struct string
|
||||
{
|
||||
string (const char *) {}
|
||||
template <class Iter> string (Iter, Iter);
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct pair
|
||||
{
|
||||
pair (T t, U u) {}
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
struct map
|
||||
{
|
||||
void insert (pair<T,U>);
|
||||
void insert (std::initializer_list<pair<T,U> >) {}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
map<string,string> m;
|
||||
m.insert({ {"this","that"}, {"me","you"} });
|
||||
}
|
11
gcc/testsuite/g++.dg/cpp0x/initlist3.C
Normal file
11
gcc/testsuite/g++.dg/cpp0x/initlist3.C
Normal file
|
@ -0,0 +1,11 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
template <class T> void f(std::initializer_list<T>);
|
||||
|
||||
void g()
|
||||
{
|
||||
f({1,2,3});
|
||||
}
|
||||
|
32
gcc/testsuite/g++.dg/cpp0x/initlist4.C
Normal file
32
gcc/testsuite/g++.dg/cpp0x/initlist4.C
Normal file
|
@ -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" }
|
||||
};
|
21
gcc/testsuite/g++.dg/cpp0x/initlist5.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/initlist5.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Test for narrowing diagnostics
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
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<int>);
|
||||
};
|
||||
B b1 { 1, 2 }; // creates initializer_list<int> 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
|
30
gcc/testsuite/g++.dg/cpp0x/initlist6.C
Normal file
30
gcc/testsuite/g++.dg/cpp0x/initlist6.C
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Test for initlist lifetime
|
||||
// { dg-options "-std=c++0x" }
|
||||
// { dg-do run }
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
int c;
|
||||
|
||||
struct A
|
||||
{
|
||||
A(int,int) { ++c; }
|
||||
~A() { --c; }
|
||||
};
|
||||
|
||||
void f (std::initializer_list<A> l) { }
|
||||
|
||||
int main()
|
||||
{
|
||||
f({ {1,2}, {3,4} });
|
||||
if (c != 0)
|
||||
return 1;
|
||||
|
||||
{
|
||||
std::initializer_list<A> l { {1,2}, {3,4} };
|
||||
if (c != 2)
|
||||
return 2;
|
||||
}
|
||||
if (c != 0)
|
||||
return 3;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-std=c++98" }
|
||||
|
||||
template <typename... T> struct A // { dg-error "does not include variadic templates" }
|
||||
template <typename... T> 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" }
|
||||
|
|
|
@ -4,5 +4,5 @@ struct A {};
|
|||
|
||||
struct B : A
|
||||
{
|
||||
B() : A {} // { dg-error "expected" }
|
||||
B() : A {} // { dg-error "initializer|expected" }
|
||||
};
|
||||
|
|
20
gcc/tree.c
20
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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2008-07-02 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* libsupc++/initializer_list: New file.
|
||||
* include/bits/stl_map.h (insert(initializer_list)): New method.
|
||||
|
||||
2008-06-30 Alfred E. Heggestad <aeh@db.org>
|
||||
|
||||
* include/backward/backward_warning.h: Fix typo.
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
|
||||
#include <bits/functexcept.h>
|
||||
#include <bits/concept_check.h>
|
||||
#include <initializer_list>
|
||||
|
||||
_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<value_type> of pairs to be
|
||||
* inserted.
|
||||
*
|
||||
* Complexity similar to that of the range constructor.
|
||||
*
|
||||
*/
|
||||
void
|
||||
insert(std::initializer_list<value_type> 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
|
||||
|
|
64
libstdc++-v3/libsupc++/initializer_list
Normal file
64
libstdc++-v3/libsupc++/initializer_list
Normal file
|
@ -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 <cstddef>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class E>
|
||||
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
|
Loading…
Add table
Reference in a new issue