cp-tree.h (LOOKUP_LIST_ONLY): New.
authorJason Merrill <jason@redhat.com>
Wed, 12 May 2010 17:34:38 +0000 (13:34 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 12 May 2010 17:34:38 +0000 (13:34 -0400)
* cp-tree.h (LOOKUP_LIST_ONLY): New.
* call.c (add_candidates): Enforce it.
(build_new_method_call): Try non-list ctor if no viable list ctor.
(build_user_type_conversion_1): Likewise.

From-SVN: r159334

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist32.C [new file with mode: 0644]

index 3872df21d16c51766e8993fc932cca8cf5507172..97dcc8d7aec558cd5638befd9f5e267abad7e122 100644 (file)
@@ -1,5 +1,10 @@
 2010-05-12  Jason Merrill  <jason@redhat.com>
 
+       * cp-tree.h (LOOKUP_LIST_ONLY): New.
+       * call.c (add_candidates): Enforce it.
+       (build_new_method_call): Try non-list ctor if no viable list ctor.
+       (build_user_type_conversion_1): Likewise.
+
        * call.c (add_candidates): Distinguish between type(x) and
        x.operator type().
        (convert_class_to_reference): Set LOOKUP_NO_CONVERSION.
index 204a6bbcfc13bd0419ed095574c9ca21d7704a17..c618b2938af8e01166584366a09a53990d73723b 100644 (file)
@@ -2860,6 +2860,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
   if (ctors)
     {
       int ctorflags = flags;
+      bool try_single_arg = true;
       ctors = BASELINK_FUNCTIONS (ctors);
 
       first_arg = build_int_cst (build_pointer_type (totype), 0);
@@ -2868,28 +2869,44 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
          /* For list-initialization we consider explicit constructors, but
             give an error if one is selected.  */
          ctorflags &= ~LOOKUP_ONLYCONVERTING;
+         /* If the class has a list ctor, try passing the list as a single
+            argument first, but only consider list ctors.  */
          if (TYPE_HAS_LIST_CTOR (totype))
-           args = make_tree_vector_single (expr);
+           ctorflags |= LOOKUP_LIST_ONLY;
          else
-           {
-             args = ctor_to_vec (expr);
-             /* We still allow more conversions within an init-list.  */
-             ctorflags &= ~LOOKUP_NO_CONVERSION;
-             /* But not for the copy ctor.  */
-             ctorflags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
-           }
+           try_single_arg = false;
        }
-      else
-       args = make_tree_vector_single (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))
                  && !DECL_HAS_VTT_PARM_P (OVL_CURRENT (ctors)));
 
-      add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
-                     TYPE_BINFO (totype), TYPE_BINFO (totype),
-                     ctorflags, &candidates);
+      /* If EXPR is not an initializer-list, or if totype has a list
+        constructor, try EXPR as a single argument.  */
+      if (try_single_arg)
+       {
+         args = make_tree_vector_single (expr);
+         add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
+                         TYPE_BINFO (totype), TYPE_BINFO (totype),
+                         ctorflags, &candidates);
+       }
+
+      /* If we didn't find a suitable list constructor for an initializer-list,
+        try breaking it apart.  */
+      if (!candidates && BRACE_ENCLOSED_INITIALIZER_P (expr))
+       {
+         args = ctor_to_vec (expr);
+         /* We aren't looking for list-ctors anymore.  */
+         ctorflags &= ~LOOKUP_LIST_ONLY;
+         /* We still allow more conversions within an init-list.  */
+         ctorflags &= ~LOOKUP_NO_CONVERSION;
+         /* But not for the copy ctor.  */
+         ctorflags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
+         add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
+                         TYPE_BINFO (totype), TYPE_BINFO (totype),
+                         ctorflags, &candidates);
+       }
 
       for (cand = candidates; cand; cand = cand->next)
        {
@@ -4009,6 +4026,7 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
 {
   tree ctype;
   const VEC(tree,gc) *non_static_args;
+  bool check_list_ctor;
   bool check_converting;
   unification_kind_t strict;
   tree fn;
@@ -4020,6 +4038,7 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
   fn = OVL_CURRENT (fns);
   if (DECL_CONV_FN_P (fn))
     {
+      check_list_ctor = false;
       check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
       if (flags & LOOKUP_NO_CONVERSION)
        /* We're doing return_type(x).  */
@@ -4036,9 +4055,15 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
   else
     {
       if (DECL_CONSTRUCTOR_P (fn))
-       check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+       {
+         check_list_ctor = !!(flags & LOOKUP_LIST_ONLY);
+         check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+       }
       else
-       check_converting = false;
+       {
+         check_list_ctor = false;
+         check_converting = false;
+       }
       strict = DEDUCE_CALL;
       ctype = conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE;
     }
@@ -4058,6 +4083,8 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
 
       if (check_converting && DECL_NONCONVERTING_P (fn))
        continue;
+      if (check_list_ctor && !is_list_ctor (fn))
+       continue;
 
       /* Figure out which set of arguments to use.  */
       if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
@@ -6188,6 +6215,8 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
   tree orig_fns;
   VEC(tree,gc) *orig_args = NULL;
   void *p;
+  tree list = NULL_TREE;
+  bool try_normal;
 
   gcc_assert (instance != NULL_TREE);
 
@@ -6300,15 +6329,20 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
     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.  */
+     initializer, not T({ }).  If the type doesn't have a list ctor (or no
+     viable list ctor), break apart the list into separate ctor args.  */
+  try_normal = true;
   if (DECL_CONSTRUCTOR_P (fn) && args != NULL && !VEC_empty (tree, *args)
       && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0))
-      && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0))
-      && !TYPE_HAS_LIST_CTOR (basetype))
+      && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
     {
       gcc_assert (VEC_length (tree, *args) == 1);
-      *args = ctor_to_vec (VEC_index (tree, *args, 0));
+      list = VEC_index (tree, *args, 0);
+
+      if (TYPE_HAS_LIST_CTOR (basetype))
+       flags |= LOOKUP_LIST_ONLY;
+      else
+       try_normal = false;
     }
 
   first_mem_arg = instance_ptr;
@@ -6316,11 +6350,25 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
   /* Get the high-water mark for the CONVERSION_OBSTACK.  */
   p = conversion_obstack_alloc (0);
 
-  add_candidates (fns, first_mem_arg, args ? *args : NULL, optype,
-                 explicit_targs, template_only, conversion_path,
-                 access_binfo, flags, &candidates);
+  any_viable_p = false;
+  if (try_normal)
+    {
+      add_candidates (fns, first_mem_arg, user_args, optype,
+                     explicit_targs, template_only, conversion_path,
+                     access_binfo, flags, &candidates);
+      candidates = splice_viable (candidates, pedantic, &any_viable_p);
+    }
+
+  if (!any_viable_p && list)
+    {
+      VEC(tree,gc) *list_args = ctor_to_vec (list);
+      flags &= ~LOOKUP_LIST_ONLY;
+      add_candidates (fns, first_mem_arg, list_args, optype,
+                     explicit_targs, template_only, conversion_path,
+                     access_binfo, flags, &candidates);
+      candidates = splice_viable (candidates, pedantic, &any_viable_p);
+    }
 
-  candidates = splice_viable (candidates, pedantic, &any_viable_p);
   if (!any_viable_p)
     {
       if (complain & tf_error)
index df961e04856f14f4ab0ef67de8c346e036919d76..6b35fb97ebc089ab6c214d9791d2d42e8f1bc0bd 100644 (file)
@@ -4137,6 +4137,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 #define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
 /* This is the first parameter of a copy constructor.  */
 #define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
+/* We only want to consider list constructors.  */
+#define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
 
 #define LOOKUP_NAMESPACES_ONLY(F)  \
   (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
index a431f8af5033ff795f4407cde1e3c40c63e0c445..f0f5c2390a955f09a1356aff50109590b0c4ccf0 100644 (file)
@@ -1,5 +1,7 @@
 2010-05-12  Jason Merrill  <jason@redhat.com>
 
+       * g++.dg/cpp0x/initlist32.C: New.
+
        * g++.dg/template/conv11.C: New.
        * g++.dg/conversion/op1.C: Adjust expected error.
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist32.C b/gcc/testsuite/g++.dg/cpp0x/initlist32.C
new file mode 100644 (file)
index 0000000..78bbb5e
--- /dev/null
@@ -0,0 +1,21 @@
+// Test that we try normal init if no list ctor is viable.
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+struct B {};
+
+struct C
+{
+  C(B);
+};
+
+struct A
+{
+  A(std::initializer_list<int>);
+  A(B) { }
+  A(C);
+};
+
+B b;
+A a{b};