P0512R0 - Deduction from an initializer list.
authorJason Merrill <jason@redhat.com>
Thu, 13 Jul 2017 13:04:04 +0000 (09:04 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 13 Jul 2017 13:04:04 +0000 (09:04 -0400)
* pt.c (do_class_deduction): Do list deduction in two phases.

From-SVN: r250183

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/class-deduction41.C [new file with mode: 0644]

index 178b26260988c4358db4d387216bce5b91a8ece8..02214c9953b9a71d90452d5518734da95fb23e85 100644 (file)
@@ -1,3 +1,8 @@
+2017-07-12  Jason Merrill  <jason@redhat.com>
+
+       P0512R0 - Deduction from an initializer list.
+       * pt.c (do_class_deduction): Do list deduction in two phases.
+
 2017-07-12  Nathan Sidwell  <nathan@acm.org>
 
        * cp-tree.h (DECL_CONSTRUCTOR_P, DECL_MAYBE_IN_CHARGE_CONSTRUCTOR,
index bd02951cb85136f8ef5f91d69c5439830d136c9e..0df6854f6481bca0e0177b51ce8e9662e2c399f5 100644 (file)
@@ -25329,14 +25329,20 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 
   tree type = TREE_TYPE (tmpl);
 
+  bool try_list_ctor = false;
+
   vec<tree,va_gc> *args;
   if (init == NULL_TREE
       || TREE_CODE (init) == TREE_LIST)
     args = make_tree_vector_from_list (init);
-  else if (BRACE_ENCLOSED_INITIALIZER_P (init)
-          && !TYPE_HAS_LIST_CTOR (type)
-          && !is_std_init_list (type))
-    args = make_tree_vector_from_ctor (init);
+  else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+    {
+      try_list_ctor = TYPE_HAS_LIST_CTOR (type);
+      if (try_list_ctor || is_std_init_list (type))
+       args = make_tree_vector_single (init);
+      else
+       args = make_tree_vector_from_ctor (init);
+    }
   else
     args = make_tree_vector_single (init);
 
@@ -25391,13 +25397,43 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
        saw_ctor = true;
       }
 
-  if (args->length () < 2)
+  tree call = error_mark_node;
+
+  /* If this is list-initialization and the class has a list constructor, first
+     try deducing from the list as a single argument, as [over.match.list].  */
+  tree list_cands = NULL_TREE;
+  if (try_list_ctor && cands)
+    for (lkp_iterator iter (cands); iter; ++iter)
+      {
+       tree dg = *iter;
+       if (is_list_ctor (dg))
+         list_cands = lookup_add (dg, list_cands);
+      }
+  if (list_cands)
+    {
+      ++cp_unevaluated_operand;
+      call = build_new_function_call (list_cands, &args, tf_decltype);
+      --cp_unevaluated_operand;
+
+      if (call == error_mark_node)
+       {
+         /* That didn't work, now try treating the list as a sequence of
+            arguments.  */
+         release_tree_vector (args);
+         args = make_tree_vector_from_ctor (init);
+       }
+    }
+
+  /* Maybe generate an implicit deduction guide.  */
+  if (call == error_mark_node && args->length () < 2)
     {
       tree gtype = NULL_TREE;
 
       if (args->length () == 1)
+       /* Generate a copy guide.  */
        gtype = build_reference_type (type);
       else if (!saw_ctor)
+       /* Generate a default guide.  */
        gtype = type;
 
       if (gtype)
@@ -25419,22 +25455,29 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
       return error_mark_node;
     }
 
-  ++cp_unevaluated_operand;
-  tree t = build_new_function_call (cands, &args, tf_decltype);
+  if (call == error_mark_node)
+    {
+      ++cp_unevaluated_operand;
+      call = build_new_function_call (cands, &args, tf_decltype);
+      --cp_unevaluated_operand;
+    }
 
-  if (t == error_mark_node && (complain & tf_warning_or_error))
+  if (call == error_mark_node && (complain & tf_warning_or_error))
     {
       error ("class template argument deduction failed:");
-      t = build_new_function_call (cands, &args, complain | tf_decltype);
+
+      ++cp_unevaluated_operand;
+      call = build_new_function_call (cands, &args, complain | tf_decltype);
+      --cp_unevaluated_operand;
+
       if (elided)
        inform (input_location, "explicit deduction guides not considered "
                "for copy-initialization");
     }
 
-  --cp_unevaluated_operand;
   release_tree_vector (args);
 
-  return cp_build_qualified_type (TREE_TYPE (t), cp_type_quals (ptype));
+  return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype));
 }
 
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction41.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction41.C
new file mode 100644 (file)
index 0000000..5e7fa3a
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+
+struct B { };
+
+template <class T>
+struct A
+{
+  A(std::initializer_list<T>);
+  A(T, B);
+};
+
+A a { 1, B() };
+
+template <class,class> struct same;
+template <class T> struct same<T,T> { };
+
+same<decltype(a), A<int>> s;