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 <ja...@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. 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 "" }