diff mbox

C++ PATCH to C++17 class deduction from init-list

Message ID CADzB+2n7BeK+DSgHay+2KUQ5z-TGpDS1N0DqWE4a0VGr6yJREQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill July 13, 2017, 1:03 p.m. UTC
P0512 corrected the specification of C++17 class template argument
deduction to work more like constructor overload resolution in
initialization; in particular, this means that we should do the same
two-phase overload resolution for a class with a list constructor.
This patch implements that, so that e.g.

  #include <vector>
  int a[1];
  std::vector v{a, a, std::allocator<int>()};

will now work.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 7cede2ad071dbd7ab1f174465305e5568b5d311a
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jul 12 12:53:23 2017 -0400

            P0512R0 - Deduction from an initializer list.
    
            * pt.c (do_class_deduction): Do list deduction in two phases.
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bd02951..0df6854 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..5e7fa3a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction41.C
@@ -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;