diff mbox

C++ PATCH for C++17 class template argument deduction issues

Message ID CADzB+2=Cqbsn-ob4ob7zQZpPXYDdoW7KKuROGQNGt5amqsqfVg@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill March 3, 2017, 7:31 a.m. UTC
On Thu, Mar 2, 2017 at 3:26 PM, Jason Merrill <jason@redhat.com> wrote:
> On Wed, Mar 1, 2017 at 3:58 PM, Jason Merrill <jason@redhat.com> wrote:
>> On Tue, Feb 28, 2017 at 1:56 PM, Jason Merrill <jason@redhat.com> wrote:
>>> This patch implements some proposed resolutions to open issues with
>>> C++17 class template argument deduction.
>>
>> And some more:
>
> This patch handles the issues of references to members of the class
> template differently, by also allowing explicit guides to refer to
> them:

This patch adjusts some overload resolution.
commit a777aadaf635dc1ef460c5e12d2ead4292eaa6a9
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 1 16:11:26 2017 -1000

            Update overload resolution with deduction guides.
    
            * pt.c (do_class_deduction): Always build the copy guide.
            (copy_guide_p, template_guide_p): New.
            (build_deduction_guide): Remember the original constructor.
            * call.c (joust): Prefer the copy guide and non-template guides.
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index babab00..dc629b96 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9717,6 +9717,22 @@  joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
       int art2 = DECL_ARTIFICIAL (cand2->fn);
       if (art1 != art2)
 	return art2 - art1;
+
+      if (art1)
+	{
+	  /* Prefer the special copy guide over a declared copy/move
+	     constructor.  */
+	  if (copy_guide_p (cand1->fn))
+	    return 1;
+	  if (copy_guide_p (cand2->fn))
+	    return -1;
+
+	  /* Prefer a candidate generated from a non-template constructor.  */
+	  int tg1 = template_guide_p (cand1->fn);
+	  int tg2 = template_guide_p (cand2->fn);
+	  if (tg1 != tg2)
+	    return tg2 - tg1;
+	}
     }
 
   /* or, if not that, F2 is from a using-declaration, F1 is not, and the
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 31edc5f..7583672 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6288,6 +6288,8 @@  extern tree template_parm_to_arg                (tree);
 extern tree dguide_name				(tree);
 extern bool dguide_name_p			(tree);
 extern bool deduction_guide_p			(const_tree);
+extern bool copy_guide_p			(const_tree);
+extern bool template_guide_p			(const_tree);
 
 /* in repo.c */
 extern void init_repo				(void);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3b320fc..13293eb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -24852,6 +24852,35 @@  deduction_guide_p (const_tree fn)
   return false;
 }
 
+/* True if FN is the copy deduction guide, i.e. A(A)->A.  */
+
+bool
+copy_guide_p (const_tree fn)
+{
+  gcc_assert (deduction_guide_p (fn));
+  if (!DECL_ARTIFICIAL (fn))
+    return false;
+  tree parms = FUNCTION_FIRST_USER_PARMTYPE (DECL_TI_TEMPLATE (fn));
+  return (TREE_CHAIN (parms) == void_list_node
+	  && same_type_p (TREE_VALUE (parms), TREE_TYPE (DECL_NAME (fn))));
+}
+
+/* True if FN is a guide generated from a constructor template.  */
+
+bool
+template_guide_p (const_tree fn)
+{
+  gcc_assert (deduction_guide_p (fn));
+  if (!DECL_ARTIFICIAL (fn))
+    return false;
+  if (tree ctor = DECL_ABSTRACT_ORIGIN (fn))
+    {
+      tree tmpl = DECL_TI_TEMPLATE (ctor);
+      return PRIMARY_TEMPLATE_P (tmpl);
+    }
+  return false;
+}
+
 /* OLDDECL is a _DECL for a template parameter.  Return a similar parameter at
    LEVEL:INDEX, using tsubst_args and complain for substitution into non-type
    template parameter types.  Note that the handling of template template
@@ -25100,6 +25129,8 @@  build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
   TREE_TYPE (ded_tmpl) = TREE_TYPE (ded_fn);
   DECL_TEMPLATE_INFO (ded_fn) = build_template_info (ded_tmpl, targs);
   DECL_PRIMARY_TEMPLATE (ded_tmpl) = ded_tmpl;
+  if (DECL_P (ctor))
+    DECL_ABSTRACT_ORIGIN (ded_fn) = ctor;
   if (ci)
     set_constraints (ded_tmpl, ci);
 
@@ -25153,7 +25184,6 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
     }
 
   bool saw_ctor = false;
-  bool saw_copy = false;
   if (CLASSTYPE_METHOD_VEC (type))
     // FIXME cache artificial deduction guides
     for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
@@ -25163,16 +25193,6 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
 	cands = ovl_cons (guide, cands);
 
 	saw_ctor = true;
-
-	tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn);
-	if (parms && sufficient_parms_p (TREE_CHAIN (parms)))
-	  {
-	    tree pt = TREE_VALUE (parms);
-	    if (TREE_CODE (pt) == REFERENCE_TYPE
-		&& (same_type_ignoring_top_level_qualifiers_p
-		    (TREE_TYPE (pt), type)))
-	      saw_copy = true;
-	  }
       }
 
   if (!saw_ctor && args->length() == 0)
@@ -25180,7 +25200,7 @@  do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
       tree guide = build_deduction_guide (type, outer_args, complain);
       cands = ovl_cons (guide, cands);
     }
-  if (!saw_copy && args->length() == 1)
+  if (args->length() == 1)
     {
       tree guide = build_deduction_guide (build_reference_type (type),
 					  outer_args, complain);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C
new file mode 100644
index 0000000..129e29e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction36.C
@@ -0,0 +1,15 @@ 
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+  A(T&);
+  A(const A&);
+};
+
+int i;
+A a = i;
+A a2 = a;
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+same<decltype(a),A<int>> s1;
+same<decltype(a2),A<int>> s2;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C
new file mode 100644
index 0000000..fe6c200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction38.C
@@ -0,0 +1,27 @@ 
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+  using value_type = T;
+  A(value_type); // #1
+  A(const A&); // #2
+  A(T, T, int); // #3
+  template<class U> A(int, T, U); // #4
+}; // A(A); #5, the copy deduction candidate
+
+A x (1, 2, 3); // uses #3, generated from a non-template constructor
+
+template <class T> A(T) -> A<T>;  // #6, less specialized than #5
+
+A a (42); // uses #6 to deduce A<int> and #1 to initialize
+A b = a;  // uses #5 to deduce A<int> and #2 to initialize
+
+template <class T> A(A<T>) -> A<A<T>>;  // #7, as specialized as #5
+
+A b2 = a;  // uses #7 to deduce A<A<int>> and #1 to initialize
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+same<decltype(a),A<int>> s1;
+same<decltype(b),A<int>> s2;
+same<decltype(b2),A<A<int>>> s3;