Implement WG21 N2672, Initializer List proposed wording
authorJason Merrill <jason@redhat.com>
Wed, 2 Jul 2008 15:38:50 +0000 (11:38 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 2 Jul 2008 15:38:50 +0000 (11:38 -0400)
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

31 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/init.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/initlist1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/inherit/error4.C
gcc/testsuite/g++.dg/init/brace2.C
gcc/testsuite/g++.dg/init/brace6.C
gcc/testsuite/g++.dg/parse/crash36.C
gcc/testsuite/g++.dg/parse/ctor3.C
gcc/tree.c
gcc/tree.h
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_map.h
libstdc++-v3/libsupc++/initializer_list [new file with mode: 0644]

index 916d1b0244a506ddbb2c50331fe115601e2a03bb..fad92a66f41e482cd8350eda7034b62fddc45df3 100644 (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
index 8aff706f9db9318f754995f93565cec8468dec74..3bf8c97596df5aaa281563e0caa4fbf91280d5dc 100644 (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.
index 7f4c0168483d93fdd3d312385471a0164bbac02f..d41465db638451ff19deee95e619622d4b5c22fc 100644 (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"
index d090d8ff0e2fc21eca485b83555cc609e44d0ff0..ed6ae0e810a6163198d89e4f0ee29d4aa24be5ce 100644 (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);
index b2c17c547dbc89222b7124a78dded62093c6fbd3..70ef00a4fce6db9c9092848a473dee0c946797d7 100644 (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]).  */
index c6ae93e6104343fcdb49e4a1f2198e2105bcc7bf..a5a5574d7b4d29061462fde72dd41cb814f99133 100644 (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)
     {
index 55e620a6b542aaae8ee607adde9891ade30d55e0..80aa6e962d2344ee2ef0bb138b14e40bdb273648 100644 (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");
 }
index 0c38a7fcb0cf217391c4ad631eb744d9b31fe5a6..3e9e612f2b49cd6cdc0ba081b37cd52e410d6f79 100644 (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
index 290cb7030b537780600574e24cd3daf6d237af7f..e42f60afba79229771016af932f029bfbf140c78 100644 (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));
index 7d530f50714c552ed8139917a39a1589da1eabb6..2323c6721665886ac4430ea8e18c9a4b9d1d9776 100644 (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,25 +14140,46 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
        initializer = fold_non_dependent_expr (initializer);
     }
   else
+    initializer = cp_parser_braced_list (parser, non_constant_p);
+
+  return initializer;
+}
+
+/* Parse a brace-enclosed initializer list.
+
+   braced-init-list:
+     { initializer-list , [opt] }
+     { }
+
+   Returns a CONSTRUCTOR.  The CONSTRUCTOR_ELTS will be
+   the elements of the initializer-list (or NULL, if the last
+   production is used).  The TREE_TYPE for the CONSTRUCTOR will be
+   NULL_TREE.  There is no way to detect whether or not the optional
+   trailing `,' was provided.  NON_CONSTANT_P is as for
+   cp_parser_initializer.  */     
+
+static tree
+cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
+{
+  tree initializer;
+
+  /* Consume the `{' token.  */
+  cp_lexer_consume_token (parser->lexer);
+  /* Create a CONSTRUCTOR to represent the braced-initializer.  */
+  initializer = make_node (CONSTRUCTOR);
+  /* If it's not a `}', then there is a non-trivial initializer.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
     {
-      /* Consume the `{' token.  */
-      cp_lexer_consume_token (parser->lexer);
-      /* Create a CONSTRUCTOR to represent the braced-initializer.  */
-      initializer = make_node (CONSTRUCTOR);
-      /* If it's not a `}', then there is a non-trivial initializer.  */
-      if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
-       {
-         /* Parse the initializer list.  */
-         CONSTRUCTOR_ELTS (initializer)
-           = cp_parser_initializer_list (parser, non_constant_p);
-         /* A trailing `,' token is allowed.  */
-         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
-           cp_lexer_consume_token (parser->lexer);
-       }
-      /* Now, there should be a trailing `}'.  */
-      cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>");
+      /* Parse the initializer list.  */
+      CONSTRUCTOR_ELTS (initializer)
+       = cp_parser_initializer_list (parser, non_constant_p);
+      /* A trailing `,' token is allowed.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       cp_lexer_consume_token (parser->lexer);
     }
-
+  /* Now, there should be a trailing `}'.  */
+  cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>");
+  TREE_TYPE (initializer) = init_list_type_node;
   return initializer;
 }
 
@@ -17297,11 +17392,22 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
 {
   tree expression_list;
   tree cast;
+  bool nonconst_p;
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+    {
+      maybe_warn_cpp0x ("extended initializer lists");
+      expression_list = cp_parser_braced_list (parser, &nonconst_p);
+      CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1;
+      if (TREE_CODE (type) == TYPE_DECL)
+       type = TREE_TYPE (type);
+      return finish_compound_literal (type, expression_list);
+    }
 
   expression_list
     = cp_parser_parenthesized_expression_list (parser, false,
                                               /*cast_p=*/true,
-                                               /*allow_expansion_p=*/true,
+                                              /*allow_expansion_p=*/true,
                                               /*non_constant_p=*/NULL);
 
   cast = build_functional_cast (type, expression_list,
@@ -17352,6 +17458,22 @@ cp_parser_save_member_function_body (cp_parser* parser,
   /* Save away the tokens that make up the body of the
      function.  */
   first = parser->lexer->next_token;
+  /* We can have braced-init-list mem-initializers before the fn body.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+    {
+      cp_lexer_consume_token (parser->lexer);
+      while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
+            && cp_lexer_next_token_is_not_keyword (parser->lexer, RID_TRY))
+       {
+         /* cache_group will stop after an un-nested { } pair, too.  */
+         if (cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0))
+           break;
+
+         /* variadic mem-inits have ... after the ')'.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+           cp_lexer_consume_token (parser->lexer);
+       }
+    }
   cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
   /* Handle function try blocks.  */
   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
@@ -18210,41 +18332,54 @@ cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
   parser->object_scope = NULL_TREE;
 }
 
-/* Consume tokens up through a non-nested END token.  */
+/* Consume tokens up through a non-nested END token.  Returns TRUE if we
+   encounter the end of a block before what we were looking for.  */
 
-static void
+static bool
 cp_parser_cache_group (cp_parser *parser,
                       enum cpp_ttype end,
                       unsigned depth)
 {
   while (true)
     {
-      cp_token *token;
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
 
-      /* Abort a parenthesized expression if we encounter a brace.  */
+      /* Abort a parenthesized expression if we encounter a semicolon.  */
       if ((end == CPP_CLOSE_PAREN || depth == 0)
-         && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
-       return;
+         && token->type == CPP_SEMICOLON)
+       return true;
       /* If we've reached the end of the file, stop.  */
-      if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)
+      if (token->type == CPP_EOF
          || (end != CPP_PRAGMA_EOL
-             && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL)))
-       return;
-      /* Consume the next token.  */
-      token = cp_lexer_consume_token (parser->lexer);
+             && token->type == CPP_PRAGMA_EOL))
+       return true;
+      if (token->type == CPP_CLOSE_BRACE && depth == 0)
+       /* We've hit the end of an enclosing block, so there's been some
+          kind of syntax error.  */
+       return true;
+
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
       /* See if it starts a new group.  */
       if (token->type == CPP_OPEN_BRACE)
        {
          cp_parser_cache_group (parser, CPP_CLOSE_BRACE, depth + 1);
+         /* In theory this should probably check end == '}', but
+            cp_parser_save_member_function_body needs it to exit
+            after either '}' or ')' when called with ')'.  */
          if (depth == 0)
-           return;
+           return false;
        }
       else if (token->type == CPP_OPEN_PAREN)
-       cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1);
+       {
+         cp_parser_cache_group (parser, CPP_CLOSE_PAREN, depth + 1);
+         if (depth == 0 && end == CPP_CLOSE_PAREN)
+           return false;
+       }
       else if (token->type == CPP_PRAGMA)
        cp_parser_cache_group (parser, CPP_PRAGMA_EOL, depth + 1);
       else if (token->type == end)
-       return;
+       return false;
     }
 }
 
@@ -20503,10 +20638,10 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
                  if (CLASS_TYPE_P (TREE_TYPE (decl))
                      || type_dependent_expression_p (decl))
                    {
-                     bool is_parenthesized_init, is_non_constant_init;
+                     bool is_direct_init, is_non_constant_init;
 
                      init = cp_parser_initializer (parser,
-                                                   &is_parenthesized_init,
+                                                   &is_direct_init,
                                                    &is_non_constant_init);
 
                      cp_finish_decl (decl, init, !is_non_constant_init,
index f24b6ff04b30e17ad3e29bcac4567b9d34080610..cce706f0705d3f1ce3fb0aa6db44a93ac2a5bf83 100644 (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,
               }
           }
 
+       r = build_constructor (init_list_type_node, n);
+
        if (TREE_HAS_CONSTRUCTOR (t))
-         return finish_compound_literal (type, n);
+         return finish_compound_literal (type, r);
 
-       return build_constructor (NULL_TREE, n);
+       return r;
       }
 
     case TYPEID_EXPR:
@@ -12271,6 +12274,8 @@ type_unification_real (tree tparms,
          arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg,
                                                          arg_expr);
 
+       if (arg == init_list_type_node && arg_expr)
+         arg = arg_expr;
        if (unify (tparms, targs, parm, arg, arg_strict))
          return 1;
       }
@@ -13037,7 +13042,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
   if (arg == error_mark_node)
     return 1;
-  if (arg == unknown_type_node)
+  if (arg == unknown_type_node
+      || arg == init_list_type_node)
     /* We can't deduce anything from this, but we might get all the
        template args from other function args.  */
     return 0;
@@ -13049,6 +13055,31 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
   if (arg == parm && !uses_template_parms (parm))
     return 0;
 
+  /* Handle init lists early, so the rest of the function can assume
+     we're dealing with a type. */
+  if (BRACE_ENCLOSED_INITIALIZER_P (arg))
+    {
+      tree elt, elttype;
+      unsigned i;
+
+      if (!is_std_init_list (parm))
+       /* We can only deduce from an initializer list argument if the
+          parameter is std::initializer_list; otherwise this is a
+          non-deduced context. */
+       return 0;
+
+      elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
+
+      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (arg), i, elt)
+       {
+         if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
+           elt = TREE_TYPE (elt);
+         if (unify (tparms, targs, elttype, elt, UNIFY_ALLOW_NONE))
+           return 1;
+       }
+      return 0;
+    }
+
   /* Immediately reject some pairs that won't unify because of
      cv-qualification mismatches.  */
   if (TREE_CODE (arg) == TREE_CODE (parm)
index 1dcd785371a7c19190af61cabd9b43e951d647ef..8a36f0b77b7d55c548799fa4c8b5a87ff32ab913 100644 (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,
index 2400aeb37da258d4ee4ef16ae767cc53d336efc9..fa65e9b28048a99a606cdc4f182723bef4b31d80 100644 (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
index ff372206ee673c012d6836c69812a1cdb2518fa6..b7c0a8d33b819b9863a565cb43f1e2086c8a2d13 100644 (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
index 05e88b9002ecd95d7c91a65bcdafc9ba960e786c..4cf8021964f591ab995e6d5027c54e6da54e8174 100644 (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)
 }
 
 \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);
 
@@ -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);
+}
 \f
 /* Set of flags used within process_init_constructor to describe the
    initializers.  */
@@ -828,7 +891,7 @@ process_init_constructor_array (tree type, tree init)
       else
        ce->index = size_int (i);
       gcc_assert (ce->value);
-      ce->value = digest_init (TREE_TYPE (type), ce->value);
+      ce->value = digest_init_r (TREE_TYPE (type), ce->value, true);
 
       if (ce->value != error_mark_node)
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -854,7 +917,7 @@ process_init_constructor_array (tree type, tree init)
               next = build_functional_cast (TREE_TYPE (type), NULL_TREE,
                                             tf_warning_or_error);
            else
-               next = build_constructor (NULL_TREE, NULL);
+             next = build_constructor (init_list_type_node, NULL);
            next = digest_init (TREE_TYPE (type), next);
          }
        else if (!zero_init_p (TREE_TYPE (type)))
@@ -929,7 +992,7 @@ process_init_constructor_record (tree type, tree init)
            }
 
          gcc_assert (ce->value);
-         next = digest_init (TREE_TYPE (field), ce->value);
+         next = digest_init_r (TREE_TYPE (field), ce->value, true);
          ++idx;
        }
       else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
@@ -942,9 +1005,9 @@ process_init_constructor_record (tree type, tree init)
            next = build_functional_cast (TREE_TYPE (field), NULL_TREE,
                                           tf_warning_or_error);
          else
-           next = build_constructor (NULL_TREE, NULL);
+           next = build_constructor (init_list_type_node, NULL);
 
-         next = digest_init (TREE_TYPE (field), next);
+         next = digest_init_r (TREE_TYPE (field), next, true);
 
          /* Warn when some struct elements are implicitly initialized.  */
          warning (OPT_Wmissing_field_initializers,
@@ -1037,7 +1100,7 @@ process_init_constructor_union (tree type, tree init)
     }
 
   if (ce->value && ce->value != error_mark_node)
-    ce->value = digest_init (TREE_TYPE (ce->index), ce->value);
+    ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true);
 
   return picflag_from_initializer (ce->value);
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist1.C b/gcc/testsuite/g++.dg/cpp0x/initlist1.C
new file mode 100644 (file)
index 0000000..b7583da
--- /dev/null
@@ -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});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist2.C b/gcc/testsuite/g++.dg/cpp0x/initlist2.C
new file mode 100644 (file)
index 0000000..2fe4770
--- /dev/null
@@ -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"} });
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist3.C b/gcc/testsuite/g++.dg/cpp0x/initlist3.C
new file mode 100644 (file)
index 0000000..412deb5
--- /dev/null
@@ -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});
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist4.C b/gcc/testsuite/g++.dg/cpp0x/initlist4.C
new file mode 100644 (file)
index 0000000..d1ffab8
--- /dev/null
@@ -0,0 +1,32 @@
+// Test for initializer-list 'explicit' rule
+// { dg-options "-std=c++0x" }
+
+struct A
+{
+  explicit A(int,int);
+  operator bool();
+};
+
+A f(A)
+{
+  A{1,2};
+  A a1{1,2};
+  new A{1,2};
+  if (A a5{1,2});
+
+  A({1,2});                    // { dg-error "explicit" }
+  A a2({1,2});                 // { dg-error "explicit" }
+  A a3 = {1,2};                        // { dg-error "explicit" }
+  new A({1,2});                        // { dg-error "explicit" }
+  f({1,2});                    // { dg-error "explicit" }
+  a1 = {1,2};                  // { dg-error "explicit" }
+  if (A a4 = {1,2});           // { dg-error "explicit" }
+  return {1,2};                        // { dg-error "explicit" }
+}
+
+struct B
+{
+  A a;
+  B(): a{1,2} {}
+  B(const B&): a({1,2}) {}     // { dg-error "explicit" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist5.C b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
new file mode 100644 (file)
index 0000000..0d02fd4
--- /dev/null
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist6.C b/gcc/testsuite/g++.dg/cpp0x/initlist6.C
new file mode 100644 (file)
index 0000000..5235703
--- /dev/null
@@ -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;
+}
index 77fa75d19945bc81e3349689d73dd981305dad76..d56d67f7556663608685eee0a6a6f4deabda7264 100644 (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;
 }
index 2af063d5f5668e165bb550a31be90de8850317b7..619a20f3c70654c075c445c4ff791b4feeccf0f8 100644 (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" }
index ffb70118f9e8da74b9683f7f1202f23ad516e61d..066d1ba65ff0168a524421b7e7605c14cfef8ab4 100644 (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 };
 }
index bcd96e4ec1f91b2811abf4de9a8b019b73bc5850..1397e87d256df886c2fa9bf178d62500d6dd1092 100644 (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" }
index 193ffae24fef811aabc8a5665f5b443e520e3258..e597d926f40d2032b2cc4b1c6adc4a95e38b3d77 100644 (file)
@@ -4,5 +4,5 @@ struct A {};
 
 struct B : A
 {
-  B() : A {} // { dg-error "expected" }
+  B() : A {}                   // { dg-error "initializer|expected" }
 };
index d9e4e7f18dbf845b930ad3f1bcdc179bb1d6270a..a8f66dbb895898ed23e0905b3f3664738b8e838a 100644 (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;
+}
 \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,
index c00ad54cf05cdf9d6cbdf6029af2f5f1e74d5004..e6b9f9cf65e5789468ba6e5e3dc82feb2dc75925 100644 (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;
index 42a56a22a93edac25ee1f48dea08c4e9fc09da92..4c3689e34213aa6dac900a8e622483841c0e4013 100644 (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.
index a9486708ffef074987a8b72d6f34ac28c792234a..cf0c16bc42d14c823f500804f780af1ca27d0149 100644 (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
diff --git a/libstdc++-v3/libsupc++/initializer_list b/libstdc++-v3/libsupc++/initializer_list
new file mode 100644 (file)
index 0000000..1a3cba3
--- /dev/null
@@ -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