+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
+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.
ck_ref_bind,
ck_user,
ck_ambig,
+ ck_list,
+ ck_aggr,
ck_rvalue
} conversion_kind;
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 {
/* 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. */
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 **);
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;
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. */
else
return NULL;
+ if (flags & LOOKUP_NO_NARROWING)
+ conv->check_narrowing = true;
+
return conv;
}
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))
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;
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
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
{
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))
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)
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)
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;
};
break;
}
+ if (convs->check_narrowing)
+ check_narrowing (totype, expr);
+
if (issue_conversion_warnings)
expr = convert_and_check (totype, expr);
else
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);
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;
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
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)
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"
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.
CPTI_CLASS_TYPE,
CPTI_UNKNOWN_TYPE,
+ CPTI_INIT_LIST_TYPE,
CPTI_VTBL_TYPE,
CPTI_VTBL_PTR_TYPE,
CPTI_STD,
#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]
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
/* 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;
#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) \
/* 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. */
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) \
#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))
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);
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 */
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);
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);
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);
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);
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);
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]). */
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.) */
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
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)
{
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)
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.
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);
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)
{
/* 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
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);
{
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;
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;
}
}
}
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)
{
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:
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");
}
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
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));
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
(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 *);
(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 *);
}
/* 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;
}
}
}
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));
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;
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. */
{
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;
= 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,
condition:
expression
- type-specifier-seq declarator = assignment-expression
+ type-specifier-seq declarator = initializer-clause
+ type-specifier-seq declarator braced-init-list
GNU Extension:
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);
cp_finish_decl (decl,
initializer, !non_constant_p,
asm_specification,
- LOOKUP_ONLYCONVERTING);
+ flags);
if (pushed_scope)
pop_scope (pushed_scope);
break ;
continue ;
return expression [opt] ;
+ return braced-init-list ;
goto identifier ;
GNU extension:
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);
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
mem-initializer:
mem-initializer-id ( expression-list [opt] )
+ mem-initializer-id braced-init-list
GNU extension:
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)
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;
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)
{
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;
/* Parse the initializer. */
initializer = NULL_TREE;
- is_parenthesized_init = false;
+ is_direct_init = false;
is_non_constant_init = true;
if (is_initialized)
{
}
else
initializer = cp_parser_initializer (parser,
- &is_parenthesized_init,
+ &is_direct_init,
&is_non_constant_init);
}
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");
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)
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;
/* 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;
/*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. */
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)
initializer = fold_non_dependent_expr (initializer);
}
else
+ initializer = cp_parser_braced_list (parser, non_constant_p);
+
+ return initializer;
+}
+
+/* Parse a brace-enclosed initializer list.
+
+ braced-init-list:
+ { initializer-list , [opt] }
+ { }
+
+ Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be
+ the elements of the initializer-list (or NULL, if the last
+ production is used). The TREE_TYPE for the CONSTRUCTOR will be
+ NULL_TREE. There is no way to detect whether or not the optional
+ trailing `,' was provided. NON_CONSTANT_P is as for
+ cp_parser_initializer. */
+
+static tree
+cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
+{
+ tree initializer;
+
+ /* Consume the `{' token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Create a CONSTRUCTOR to represent the braced-initializer. */
+ initializer = make_node (CONSTRUCTOR);
+ /* If it's not a `}', then there is a non-trivial initializer. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
{
- /* Consume the `{' token. */
- cp_lexer_consume_token (parser->lexer);
- /* Create a CONSTRUCTOR to represent the braced-initializer. */
- initializer = make_node (CONSTRUCTOR);
- /* If it's not a `}', then there is a non-trivial initializer. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
- {
- /* Parse the initializer list. */
- CONSTRUCTOR_ELTS (initializer)
- = cp_parser_initializer_list (parser, non_constant_p);
- /* A trailing `,' token is allowed. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
- cp_lexer_consume_token (parser->lexer);
- }
- /* Now, there should be a trailing `}'. */
- cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>");
+ /* Parse the initializer list. */
+ CONSTRUCTOR_ELTS (initializer)
+ = cp_parser_initializer_list (parser, non_constant_p);
+ /* A trailing `,' token is allowed. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ cp_lexer_consume_token (parser->lexer);
}
-
+ /* Now, there should be a trailing `}'. */
+ cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>");
+ TREE_TYPE (initializer) = init_list_type_node;
return initializer;
}
{
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,
/* 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))
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;
}
}
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,
bool process_index_p;
int newlen;
bool need_copy_p = false;
+ tree r;
if (type == error_mark_node)
return error_mark_node;
}
}
+ r = build_constructor (init_list_type_node, n);
+
if (TREE_HAS_CONSTRUCTOR (t))
- return finish_compound_literal (type, n);
+ return finish_compound_literal (type, r);
- return build_constructor (NULL_TREE, n);
+ return r;
}
case TYPEID_EXPR:
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;
}
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;
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)
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);
{
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;
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;
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;
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;
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,
}
/* 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;
}
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;
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
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
#include "toplev.h"
#include "output.h"
#include "diagnostic.h"
+#include "real.h"
static tree
process_init_constructor (tree type, 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
}
\f
+/* 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);
{
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);
|| 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)
}
}
+tree
+digest_init (tree type, tree init)
+{
+ return digest_init_r (type, init, false);
+}
\f
/* Set of flags used within process_init_constructor to describe the
initializers. */
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
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)))
}
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)))
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,
}
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);
}
--- /dev/null
+// 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});
+}
--- /dev/null
+// 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"} });
+}
--- /dev/null
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+template <class T> void f(std::initializer_list<T>);
+
+void g()
+{
+ f({1,2,3});
+}
+
--- /dev/null
+// 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" }
+};
--- /dev/null
+// 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
--- /dev/null
+// 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;
+}
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;
}
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" }
};
struct B {
- B(const B&);
+ B(const B&); // { dg-error "candidate" }
int b;
};
{
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 };
}
// { 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" }
struct B : A
{
- B() : A {} // { dg-error "expected" }
+ B() : A {} // { dg-error "initializer|expected" }
};
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;
+}
\f
/* Return the size nominally occupied by an object of type TYPE
when it resides in memory. The value is measured in units of bytes,
/* 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
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;
+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.
#include <bits/functexcept.h>
#include <bits/concept_check.h>
+#include <initializer_list>
_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
--- /dev/null
+// 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