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:
Jason Merrill 2008-07-02 11:38:50 -04:00 committed by Jason Merrill
parent 906c5773db
commit 0935784671
31 changed files with 1214 additions and 276 deletions

View file

@ -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

View file

@ -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.

View file

@ -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"

View file

@ -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);

View file

@ -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]). */

View file

@ -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)
{

View file

@ -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");
}

View file

@ -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

View file

@ -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));

View file

@ -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,

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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);
}

View 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});
}

View 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"} });
}

View 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});
}

View 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" }
};

View 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

View 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;
}

View file

@ -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;
}

View file

@ -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" }

View file

@ -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 };
}

View file

@ -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" }

View file

@ -4,5 +4,5 @@ struct A {};
struct B : A
{
B() : A {} // { dg-error "expected" }
B() : A {} // { dg-error "initializer|expected" }
};

View file

@ -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,

View file

@ -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;

View file

@ -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.

View file

@ -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

View 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