Hi,

some time ago I started analyzing the bugs in Bugzilla involving crashes for too deep recursive template instantiation and figured out that this subset is probably the simplest to tackle (https://gcc.gnu.org/ml/gcc-patches/2013-08/msg01348.html). All these crashes involve instantiate_class_template_1 *before* the existing push_tinst_level check, via most_specialized_class, and I think it makes sense to protect it in a way very similar to that used in maybe_instantiate_noexcept. Lately I also tried simply moving the existing check before most_specialized_class and it mostly worked for C++, but regressions showed up in the libstdc++-v3 testsuite (mostly in 20_util). As regards the testcases, template/recurse.C is tweaked because the diagnostic about template instantiation depth exceed is exactly the same but isn't duplicated anymore.

Anyway, tested x86_64-linux.

Thanks,
Paolo.

/////////////////////////
/cp
2014-07-01  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/51488
        PR c++/53618
        PR c++/58059
        * pt.c (instantiate_class_template_1): Call push_tinst_level /
        pop_tinst_level around most_specialized_class.

/testsuite
2014-07-01  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/51488
        PR c++/53618
        PR c++/58059
        * g++.dg/cpp0x/template-recurse1.C: New.
        * g++.dg/template/recurse4.C: Likewise.
        * g++.dg/template/recurse.C: Adjust.
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 212204)
+++ cp/pt.c     (working copy)
@@ -8905,8 +8911,15 @@ instantiate_class_template_1 (tree type)
   gcc_assert (TREE_CODE (templ) == TEMPLATE_DECL);
 
   /* Determine what specialization of the original template to
-     instantiate.  */
-  t = most_specialized_class (type, tf_warning_or_error);
+     instantiate. Note: protect vs too deep instantiation.  */
+  if (push_tinst_level (type))
+    {
+      t = most_specialized_class (type, tf_warning_or_error);
+      pop_tinst_level ();
+    }
+  else
+    t = error_mark_node;
+
   if (t == error_mark_node)
     {
       TYPE_BEING_DEFINED (type) = 1;
Index: testsuite/g++.dg/cpp0x/template-recurse1.C
===================================================================
--- testsuite/g++.dg/cpp0x/template-recurse1.C  (revision 0)
+++ testsuite/g++.dg/cpp0x/template-recurse1.C  (working copy)
@@ -0,0 +1,25 @@
+// PR c++/58059
+// { dg-do compile { target c++11 } }
+
+template<bool, typename T = void> struct enable_if { typedef T type; };
+template<typename T> struct enable_if<false, T> { };
+
+// This code is nonsense; it was produced by minimizing the problem repeatedly.
+constexpr bool test_func(int value) {
+  return true;
+}
+template <int TParm, class Enable=void>
+struct test_class {
+  static constexpr int value = 0;
+};
+template <int TParm>
+struct test_class<
+    TParm,
+    // This line ultimately causes the crash.
+    typename enable_if<test_func(test_class<TParm-1>::value)>::type  // { 
dg-error "depth exceeds" }
+    > {
+  static constexpr int value = 1;
+};
+
+// This instantiation is required in order to crash.
+template class test_class<2,void>;
Index: testsuite/g++.dg/template/recurse.C
===================================================================
--- testsuite/g++.dg/template/recurse.C (revision 212204)
+++ testsuite/g++.dg/template/recurse.C (working copy)
@@ -5,9 +5,7 @@ template <int I> struct F
 {
   int operator()()
     {
-      F<I+1> f;                        // { dg-error "incomplete type" 
"incomplete" }
-                               // { dg-bogus "exceeds maximum.*exceeds 
maximum" "exceeds" { xfail *-*-* } 8 }
-                                // { dg-error "exceeds maximum" "exceeds" { 
xfail *-*-* } 8 }
+      F<I+1> f;                        // { dg-error "depth 
exceeds|incomplete" }
       return f()*I;             // { dg-message "recursively" "recurse" }
     }
 };
Index: testsuite/g++.dg/template/recurse4.C
===================================================================
--- testsuite/g++.dg/template/recurse4.C        (revision 0)
+++ testsuite/g++.dg/template/recurse4.C        (working copy)
@@ -0,0 +1,5 @@
+// PR c++/51488
+
+template<class T,class U=void> struct s;
+template<class T> struct s<T,typename s<T>::a> {};
+s<int> ca;  // { dg-error "depth exceeds|incomplete" }

Reply via email to