re PR c++/44175 ([C++0x] decltype sometimes cannot recurse)
authorJason Merrill <jason@redhat.com>
Wed, 1 Jun 2011 20:27:22 +0000 (16:27 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 1 Jun 2011 20:27:22 +0000 (16:27 -0400)
PR c++/44175
* pt.c (template_args_equal): Handle one arg being NULL_TREE.
(deduction_tsubst_fntype): Handle excessive non-infinite recursion.

From-SVN: r174543

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

index 921f98f11ac588fae6fa711d9e49d2d7cb7330e7..bf79bb6891713491159a612187389634f26b21e6 100644 (file)
@@ -1,5 +1,9 @@
 2011-06-01  Jason Merrill  <jason@redhat.com>
 
+       PR c++/44175
+       * pt.c (template_args_equal): Handle one arg being NULL_TREE.
+       (deduction_tsubst_fntype): Handle excessive non-infinite recursion.
+
        PR c++/49253
        * typeck2.c (build_x_arrow): Don't use build_min_nt.
 
index ae3d83da39db5f38aa44d4746d1c4080850275ce..c1bee3e05523c06a1bae9c9e464757b16562514c 100644 (file)
@@ -6476,6 +6476,8 @@ template_args_equal (tree ot, tree nt)
 {
   if (nt == ot)
     return 1;
+  if (nt == NULL_TREE || ot == NULL_TREE)
+    return false;
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
@@ -13598,7 +13600,14 @@ static GTY((param_is (spec_entry))) htab_t current_deduction_htab;
 /* In C++0x, it's possible to have a function template whose type depends
    on itself recursively.  This is most obvious with decltype, but can also
    occur with enumeration scope (c++/48969).  So we need to catch infinite
-   recursion and reject the substitution at deduction time.
+   recursion and reject the substitution at deduction time; this function
+   will return error_mark_node for any repeated substitution.
+
+   This also catches excessive recursion such as when f<N> depends on
+   f<N-1> across all integers, and returns error_mark_node for all the
+   substitutions back up to the initial one.
+
+   This is, of course, not reentrant.
 
    Use of a VEC here is O(n^2) in the depth of function template argument
    deduction substitution, but using a hash table creates a lot of constant
@@ -13611,6 +13620,8 @@ static GTY((param_is (spec_entry))) htab_t current_deduction_htab;
 static tree
 deduction_tsubst_fntype (tree fn, tree targs)
 {
+  static bool excessive_deduction_depth;
+
   unsigned i;
   spec_entry **slot;
   spec_entry *p;
@@ -13656,6 +13667,14 @@ deduction_tsubst_fntype (tree fn, tree targs)
   /* If we've created a hash table, look there.  */
   if (current_deduction_htab)
     {
+      if (htab_elements (current_deduction_htab)
+         > (unsigned) max_tinst_depth)
+       {
+         /* Trying to recurse across all integers or some such.  */
+         excessive_deduction_depth = true;
+         return error_mark_node;
+       }
+
       hash = hash_specialization (&elt);
       slot = (spec_entry **)
        htab_find_slot_with_hash (current_deduction_htab, &elt, hash, INSERT);
@@ -13701,6 +13720,13 @@ deduction_tsubst_fntype (tree fn, tree targs)
        r = error_mark_node;
       VEC_pop (spec_entry, current_deduction_vec);
     }
+  if (excessive_deduction_depth)
+    {
+      r = error_mark_node;
+      if (htab_elements (current_deduction_htab) == 0)
+       /* Reset once we're all the way out.  */
+       excessive_deduction_depth = false;
+    }
   return r;
 }
 
index 7e90e17f08400526d0f903fa74e9badc5c2f0dc8..7639dffac69f9937980707dd0b25425677dcc23d 100644 (file)
@@ -1,3 +1,8 @@
+2011-06-01  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/decltype28.C: New.
+       * g++.dg/cpp0x/decltype29.C: New.
+
 2011-06-01  Richard Sandiford  <rdsandiford@googlemail.com>
 
        PR target/45074
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype28.C b/gcc/testsuite/g++.dg/cpp0x/decltype28.C
new file mode 100644 (file)
index 0000000..0ab8932
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/44175
+// { dg-options -std=c++0x }
+
+template <bool, class T> struct enable_if { };
+template <class T> struct enable_if <true, T> { typedef T type; };
+
+template <class F, int N>
+void ft (F f, typename enable_if<N!=0, int>::type) {}
+
+template< class F, int N >
+decltype(ft<F, N-1> (F(), 0))
+ft (F f, typename enable_if<N==0, int>::type) {}
+
+int main() {
+  ft<struct a*, 2> (0, 0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype29.C b/gcc/testsuite/g++.dg/cpp0x/decltype29.C
new file mode 100644 (file)
index 0000000..1dd5a5f
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/44175
+// { dg-options -std=c++0x }
+
+template <bool, class T> struct enable_if { };
+template <class T> struct enable_if <true, T> { typedef T type; };
+
+template <int x>
+typename enable_if<x==0,int>::type
+ft() {}
+
+template<class F, int N>
+decltype (ft<F> (F()))
+ft() {}
+
+int main() {
+    ft<struct a*, 0>();                // { dg-error "no match" }
+}
+
+// { dg-prune-output "note" }