C++ PATCH for c++/81917, ICE with self-referential partial specialization

Message ID CADzB+2n5iTCLg3bwyix=M1uX1giL-xcmk28nf8+jyFE0v9YxyQ@mail.gmail.com
State New
Headers show
Series
  • C++ PATCH for c++/81917, ICE with self-referential partial specialization
Related show

Commit Message

Jason Merrill Feb. 9, 2018, 9:01 p.m.
In this testcase we were managing to instantiate the same class twice,
leading to an ICE.  Fixed by setting TYPE_BEING_DEFINED before we
consider what partial specialization to use.  This also causes several
existing testcases to error about incomplete types rather than excess
template instantiation depth, which seems appropriate.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 46063f6cb79e4f37040a326a2da1378e0e98cb38
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 9 14:26:03 2018 -0500

            PR c++/81917 - ICE with void_t and partial specialization.
    
            * pt.c (instantiate_class_template_1): Set TYPE_BEING_DEFINED before
            calling most_specialized_partial_spec.

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9c57709e7a7..281604594ad 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10347,14 +10347,14 @@  instantiate_class_template_1 (tree type)
   templ = most_general_template (CLASSTYPE_TI_TEMPLATE (type));
   gcc_assert (TREE_CODE (templ) == TEMPLATE_DECL);
 
+  /* Mark the type as in the process of being defined.  */
+  TYPE_BEING_DEFINED (type) = 1;
+
   /* Determine what specialization of the original template to
      instantiate.  */
   t = most_specialized_partial_spec (type, tf_warning_or_error);
   if (t == error_mark_node)
-    {
-      TYPE_BEING_DEFINED (type) = 1;
-      return error_mark_node;
-    }
+    return error_mark_node;
   else if (t)
     {
       /* This TYPE is actually an instantiation of a partial
@@ -10379,16 +10379,16 @@  instantiate_class_template_1 (tree type)
   /* If the template we're instantiating is incomplete, then clearly
      there's nothing we can do.  */
   if (!COMPLETE_TYPE_P (pattern))
-    return type;
+    {
+      /* We can try again later.  */
+      TYPE_BEING_DEFINED (type) = 0;
+      return type;
+    }
 
   /* If we've recursively instantiated too many templates, stop.  */
   if (! push_tinst_level (type))
     return type;
 
-  /* Now we're really doing the instantiation.  Mark the type as in
-     the process of being defined.  */
-  TYPE_BEING_DEFINED (type) = 1;
-
   /* We may be in the middle of deferred access check.  Disable
      it now.  */
   push_deferring_access_checks (dk_no_deferred);
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-62.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-62.C
new file mode 100644
index 00000000000..6f1fa4584ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-62.C
@@ -0,0 +1,22 @@ 
+// PR c++/81917
+// { dg-do compile { target c++11 } }
+
+template <typename> using a = void;
+template <typename, typename = void> struct b
+{
+  typedef int c;
+};
+template <typename d> class b<d, a<typename d::e>>;
+template <typename d, typename = typename b<d>::c> class f;
+template <typename> class g { };
+template <typename, typename> class h
+{
+  class i;
+  typedef g<f<i>> j;
+  class i
+  {
+    j k;			// { dg-error "incomplete" }
+  };
+};
+h<int, int> H;
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C
index 40e3075c162..0df0d4e89c3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-template2.C
@@ -1,6 +1,5 @@ 
 // PR c++/71747
 // { dg-do compile { target c++11 } }
-// { dg-options -ftemplate-depth=20 }
 
 template < bool > struct A
 {
@@ -14,10 +13,8 @@  template < bool > struct A
 template < bool, typename = int > struct F; 
 template < bool X > 
 // should be: struct F < X, typename A < A < X > {} () >::type > 
-struct F < X, typename A < F < X > {} () >::type > // { dg-error "" }
+struct F < X, typename A < F < X > {} () >::type >
 {
 };
 
-F < true > f;
-
-// { dg-prune-output "compilation terminated" }
+F < true > f;			// { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/crash125.C b/gcc/testsuite/g++.dg/template/crash125.C
index 448f74682d4..de41b99a927 100644
--- a/gcc/testsuite/g++.dg/template/crash125.C
+++ b/gcc/testsuite/g++.dg/template/crash125.C
@@ -13,6 +13,4 @@  struct TraitCheckImpl<Swappable<T> > {
     typedef void Complete;
 };
 
-Swappable<int> s;  // { dg-error "depth" }
-
-// { dg-prune-output "compilation terminated" }
+Swappable<int> s;  // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/pr51488.C b/gcc/testsuite/g++.dg/template/pr51488.C
index 4979a22787c..794a6cfe067 100644
--- a/gcc/testsuite/g++.dg/template/pr51488.C
+++ b/gcc/testsuite/g++.dg/template/pr51488.C
@@ -2,6 +2,4 @@ 
 
 template<class T,class U=void> struct s;
 template<class T> struct s<T,typename s<T>::a> {};
-s<int> ca;  // { dg-error "depth" }
-
-// { dg-prune-output "compilation terminated" }
+s<int> ca;  // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/pr55843.C b/gcc/testsuite/g++.dg/template/pr55843.C
index 467dd827218..04079ed1175 100644
--- a/gcc/testsuite/g++.dg/template/pr55843.C
+++ b/gcc/testsuite/g++.dg/template/pr55843.C
@@ -1,5 +1,3 @@ 
-// { dg-options "-ftemplate-depth-8" }
-
 template< typename T > struct type_wrapper {
 };
 typedef char (&yes_tag)[2];
@@ -7,11 +5,11 @@  template<bool b> struct if_c {
 };
 template< typename T > struct has_type {
   struct gcc_3_2_wknd {
-    template< typename U > static yes_tag test( type_wrapper<U> const volatile* // { dg-message "required" }
+    template< typename U > static yes_tag test( type_wrapper<U> const volatile* // { dg-message "" }
 , type_wrapper<typename U::type>* = 0 );
   };
   typedef type_wrapper<T> t_;
-  static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) == // { dg-message "required" }
+  static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) == // { dg-message "" }
 sizeof(yes_tag);
 };
 template <class K, class T, class=void> struct Get_type {
@@ -22,7 +20,4 @@  template <class K> struct Get_type<K, RT_tag, typename if_c<
 !has_type<Get_type<K, FT_tag> >::value >::type> { }; // { dg-message "required" }
 template <class K> struct Get_type<K, FT_tag, typename if_c<
 !has_type<Get_type<K, RT_tag> >::value >::type> { };  // { dg-message "required" }
-typedef Get_type<int, FT_tag>::type P;
-
-// { dg-prune-output "-ftemplate-depth" }
-// { dg-prune-output "compilation terminated" }
+typedef Get_type<int, FT_tag>::type P;		      // { dg-message "" }