This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/53498 (infinite tsubst recursion with variadic template)


Here, the problem was that when we substitute into a parameter pack PARM_DECL to get a dummy decl for use in a decltype context, we were continuing to tsubst into its DECL_CHAIN as well, which causes problems if a following parameter uses the previous parameter, as in this testcase.

In tsubst_copy we've dealt with this issue for non-pack parameters by doing a copy_node before calling tsubst_decl, but it occurred to me that we could check cp_unevaluated_context instead to avoid the extra allocation.

Tested x86_64-pc-linux-gnu, applying to trunk. Alternative patch that just does the copy for packs as well tested and applying to 4.7.
commit 9b1909cf6cf54f405b83e312483d263d9c4b6f92
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 25 17:02:48 2012 -0400

    	PR c++/53498
    	PR c++/53305
    	* pt.c (tsubst_decl) [PARM_DECL]: Don't recurse into DECL_CHAIN
    	if cp_unevaluated_operand is set.
    	(tsubst_copy) [PARM_DECL]: Don't copy before tsubsting.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ad7134b..7e1c46f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10497,7 +10497,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
               DECL_CHAIN (prev_r) = r;
           }
 
-	if (DECL_CHAIN (t))
+	/* If cp_unevaluated_operand is set, we're just looking for a
+	   single dummy parameter, so don't keep going.  */
+	if (DECL_CHAIN (t) && !cp_unevaluated_operand)
 	  DECL_CHAIN (r) = tsubst (DECL_CHAIN (t), args,
 				   complain, DECL_CHAIN (t));
 
@@ -12078,8 +12080,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
       if (r == NULL_TREE)
 	{
-	  tree c;
-
 	  /* We get here for a use of 'this' in an NSDMI.  */
 	  if (DECL_NAME (t) == this_identifier
 	      && at_function_scope_p ()
@@ -12090,12 +12090,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	     declaration (such as in a late-specified return type).  Just
 	     make a dummy decl, since it's only used for its type.  */
 	  gcc_assert (cp_unevaluated_operand != 0);
-	  /* We copy T because want to tsubst the PARM_DECL only,
-	     not the following PARM_DECLs that are chained to T.  */
-	  c = copy_node (t);
-	  r = tsubst_decl (c, args, complain);
-	  if (r == NULL_TREE)
-	    return error_mark_node;
+	  r = tsubst_decl (t, args, complain);
 	  /* Give it the template pattern as its context; its true context
 	     hasn't been instantiated yet and this is good enough for
 	     mangling.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype38.C b/gcc/testsuite/g++.dg/cpp0x/decltype38.C
new file mode 100644
index 0000000..97ebb33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype38.C
@@ -0,0 +1,17 @@
+// PR c++/53498
+// { dg-do compile { target c++11 } }
+
+template<typename... Args>
+struct B
+{
+  template<typename U>
+  static
+  void b(const U& u, const Args&... args,
+	 decltype(u.f(args...)) dummy)
+  {
+  }
+};
+
+int main() {
+  B<int> b;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic132.C b/gcc/testsuite/g++.dg/cpp0x/variadic132.C
index f50c7a6..1b9c286 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic132.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic132.C
@@ -9,11 +9,11 @@ struct funct
   int operator()(argTs...);
 };
 
-template<class...> class test;
+template<class...> struct test;
 
 template<template <class...> class tp,
 	 class... arg1Ts, class... arg2Ts>
-class test<tp<arg1Ts...>, tp<arg2Ts...>>
+struct test<tp<arg1Ts...>, tp<arg2Ts...>>
 {
   template<class func, class...arg3Ts>
     auto test2(func fun, arg1Ts... arg1s, arg3Ts... arg3s)
@@ -23,5 +23,5 @@ class test<tp<arg1Ts...>, tp<arg2Ts...>>
 int main()
 {
   test<tuple<>, tuple<char,int>> t2;
-  t2.test2(funct(), 'a', 2);  // { dg-error "no matching function" }
+  t2.test2(funct(), 'a', 2);
 }
commit 1965f161a59d81a408cd2369e7a393fa17e95ede
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 25 17:32:32 2012 -0400

    	PR c++/53498
    	PR c++/53305
    	* pt.c (tsubst_pack_expansion): Copy before dummy tsubst.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7f5682d..1b5ab9e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9393,7 +9393,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 		 late-specified return type).  Even if it exists, it might
 		 have the wrong value for a recursive call.  Just make a
 		 dummy decl, since it's only used for its type.  */
-	      arg_pack = tsubst_decl (parm_pack, args, complain);
+	      /* Copy before tsubsting so that we don't recurse into any
+		 later PARM_DECLs.  */
+	      arg_pack = tsubst_decl (copy_node (parm_pack), args, complain);
 	      if (arg_pack && FUNCTION_PARAMETER_PACK_P (arg_pack))
 		/* Partial instantiation of the parm_pack, we can't build
 		   up an argument pack yet.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype38.C b/gcc/testsuite/g++.dg/cpp0x/decltype38.C
new file mode 100644
index 0000000..97ebb33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype38.C
@@ -0,0 +1,17 @@
+// PR c++/53498
+// { dg-do compile { target c++11 } }
+
+template<typename... Args>
+struct B
+{
+  template<typename U>
+  static
+  void b(const U& u, const Args&... args,
+	 decltype(u.f(args...)) dummy)
+  {
+  }
+};
+
+int main() {
+  B<int> b;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic132.C b/gcc/testsuite/g++.dg/cpp0x/variadic132.C
new file mode 100644
index 0000000..1b9c286
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic132.C
@@ -0,0 +1,27 @@
+// PR c++/53305
+// { dg-do compile { target c++11 } }
+
+template<class... Ts> struct tuple { };
+
+struct funct
+{
+  template<class... argTs>
+  int operator()(argTs...);
+};
+
+template<class...> struct test;
+
+template<template <class...> class tp,
+	 class... arg1Ts, class... arg2Ts>
+struct test<tp<arg1Ts...>, tp<arg2Ts...>>
+{
+  template<class func, class...arg3Ts>
+    auto test2(func fun, arg1Ts... arg1s, arg3Ts... arg3s)
+    -> decltype(fun(arg1s..., arg3s...));
+};
+
+int main()
+{
+  test<tuple<>, tuple<char,int>> t2;
+  t2.test2(funct(), 'a', 2);
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]