re PR c++/69005 (infinite(?) recursion in template instantiations)
authorJason Merrill <jason@redhat.com>
Fri, 25 Dec 2015 03:24:51 +0000 (22:24 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 25 Dec 2015 03:24:51 +0000 (22:24 -0500)
PR c++/69005

* call.c (add_template_candidate_real): Don't try to deduce X(X).

From-SVN: r231952

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

index 02aa9b5c2c6deabe227da4fd4d6aa92a36024ef8..4c7e38452ecbd59e83439ed1c08932b48d385181 100644 (file)
@@ -1,3 +1,8 @@
+2015-12-24  Jason Merrill  <jason@redhat.com>
+
+       PR c++/69005
+       * call.c (add_template_candidate_real): Don't try to deduce X(X).
+
 2015-12-22  Jason Merrill  <jason@redhat.com>
 
        PR c++/66921
index cdfa01ac63fdc0419cb18c7c6253aa01385a799a..4f253563417facb91efc5e5c761f58bbd7fa34fa 100644 (file)
@@ -3037,6 +3037,34 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   if (len < skip_without_in_chrg)
     return NULL;
 
+  if (DECL_CONSTRUCTOR_P (tmpl) && nargs == 2
+      && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (first_arg),
+                                                   TREE_TYPE ((*arglist)[0])))
+    {
+      /* 12.8/6 says, "A declaration of a constructor for a class X is
+        ill-formed if its first parameter is of type (optionally cv-qualified)
+        X and either there are no other parameters or else all other
+        parameters have default arguments. A member function template is never
+        instantiated to produce such a constructor signature."
+
+        So if we're trying to copy an object of the containing class, don't
+        consider a template constructor that has a first parameter type that
+        is just a template parameter, as we would deduce a signature that we
+        would then reject in the code below.  */
+      if (tree firstparm = FUNCTION_FIRST_USER_PARMTYPE (tmpl))
+       {
+         firstparm = TREE_VALUE (firstparm);
+         if (PACK_EXPANSION_P (firstparm))
+           firstparm = PACK_EXPANSION_PATTERN (firstparm);
+         if (TREE_CODE (firstparm) == TEMPLATE_TYPE_PARM)
+           {
+             gcc_assert (!explicit_targs);
+             reason = invalid_copy_with_fn_template_rejection ();
+             goto fail;
+           }
+       }
+    }
+
   nargs_without_in_chrg = ((first_arg_without_in_chrg != NULL_TREE ? 1 : 0)
                           + (len - skip_without_in_chrg));
   args_without_in_chrg = XALLOCAVEC (tree, nargs_without_in_chrg);
@@ -3075,34 +3103,15 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
       goto fail;
     }
 
-  /* In [class.copy]:
-
-       A member function template is never instantiated to perform the
-       copy of a class object to an object of its class type.
-
-     It's a little unclear what this means; the standard explicitly
-     does allow a template to be used to copy a class.  For example,
-     in:
-
-       struct A {
-        A(A&);
-        template <class T> A(const T&);
-       };
-       const A f ();
-       void g () { A a (f ()); }
-
-     the member template will be used to make the copy.  The section
-     quoted above appears in the paragraph that forbids constructors
-     whose only parameter is (a possibly cv-qualified variant of) the
-     class type, and a logical interpretation is that the intent was
-     to forbid the instantiation of member templates which would then
-     have that form.  */
   if (DECL_CONSTRUCTOR_P (fn) && nargs == 2)
     {
       tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn);
       if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)),
                                    ctype))
        {
+         /* We're trying to produce a constructor with a prohibited signature,
+            as discussed above; handle here any cases we didn't catch then,
+            such as X(X<T>).  */
          reason = invalid_copy_with_fn_template_rejection ();
          goto fail;
        }
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted50.C b/gcc/testsuite/g++.dg/cpp0x/defaulted50.C
new file mode 100644 (file)
index 0000000..fea4537
--- /dev/null
@@ -0,0 +1,27 @@
+// PR c++/69005
+// { dg-do compile { target c++11 } }
+
+template<typename T> T& declval();
+
+template<typename _Sig> class function;
+
+template<typename _Res, typename _Arg>
+struct function<_Res(_Arg)>
+{
+  function() noexcept { }
+
+  function(const function&) { }
+
+  template<typename _Functor,
+          typename = decltype(declval<_Functor&>()(declval<_Arg>()))>
+  function(_Functor) { }
+
+  _Res operator()(_Arg) const;
+};
+
+struct Foo {
+  function<void(Foo)> Func;
+};
+
+extern Foo exfoo;
+Foo f (exfoo);