From patchwork Tue Dec 11 18:16:19 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: C++ PATCH for c++/54416 (ICE after error on bogus specialization) Date: Tue, 11 Dec 2012 08:16:19 -0000 From: Jason Merrill X-Patchwork-Id: 205280 Message-Id: <50C77873.8090808@redhat.com> To: gcc-patches List In this testcase we get confused by a specialization nested inside a class template; the members of the specialization end up having dependent template arguments, and then we get confused when we try to define one of them in a context that has no template headers. Fixed by rejecting the definition of the specialization, and therefore the definition of the member of the specialization. Tested x86_64-pc-linux-gnu, applying to trunk. commit 9bcbafc418c3f7aff48c8e98f362e7f44849051e Author: Jason Merrill Date: Tue Dec 11 10:59:36 2012 -0500 * pt.c (maybe_process_partial_specialization): Handle aliases first. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1bc9e1b..f30a1e1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -812,13 +812,17 @@ maybe_process_partial_specialization (tree type) context = TYPE_CONTEXT (type); - if ((CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type)) - /* Consider non-class instantiations of alias templates as - well. */ - || (TYPE_P (type) - && TYPE_TEMPLATE_INFO (type) - && DECL_LANG_SPECIFIC (TYPE_NAME (type)) - && DECL_USE_TEMPLATE (TYPE_NAME (type)))) + if (TYPE_ALIAS_P (type)) + { + if (TYPE_TEMPLATE_INFO (type) + && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (type))) + error ("specialization of alias template %qD", + TYPE_TI_TEMPLATE (type)); + else + error ("explicit specialization of non-template %qT", type); + return error_mark_node; + } + else if (CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type)) { /* This is for ordinary explicit specialization and partial specialization of a template class such as: @@ -831,8 +835,7 @@ maybe_process_partial_specialization (tree type) Make sure that `C' and `C' are implicit instantiations. */ - if (CLASS_TYPE_P (type) - && CLASSTYPE_IMPLICIT_INSTANTIATION (type) + if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) { check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)); @@ -845,16 +848,9 @@ maybe_process_partial_specialization (tree type) return error_mark_node; } } - else if (CLASS_TYPE_P (type) - && CLASSTYPE_TEMPLATE_INSTANTIATION (type)) + else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) error ("specialization of %qT after instantiation", type); - if (DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (type))) - { - error ("partial specialization of alias template %qD", - TYPE_TI_TEMPLATE (type)); - return error_mark_node; - } } else if (CLASS_TYPE_P (type) && !CLASSTYPE_USE_TEMPLATE (type) diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C index d0eda5f..cbba90f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-1.C @@ -5,10 +5,10 @@ template struct A0 {}; template using AA0 = A0; -template struct AA0 {}; // { dg-error "partial specialization" } +template struct AA0 {}; // { dg-error "specialization" } template using Ptr = U*; -template struct Ptr {}; // { dg-error "partial specialization" } +template struct Ptr {}; // { dg-error "specialization" } struct A { using A = int;//{ dg-error "nested|has|same name as|class|in which|declared" } commit e575667938e576ceeede4bdb00361d2b52540a48 Author: Jason Merrill Date: Sat Dec 8 20:16:30 2012 -0500 PR c++/54416 * pt.c (maybe_process_partial_specialization): Don't accept definition of a specialization without the appropriate header. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f30a1e1..91450d8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -850,7 +850,13 @@ maybe_process_partial_specialization (tree type) } else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) error ("specialization of %qT after instantiation", type); - + else if (errorcount && !processing_specialization + && CLASSTYPE_TEMPLATE_SPECIALIZATION (type) + && !uses_template_parms (CLASSTYPE_TI_ARGS (type))) + /* Trying to define a specialization either without a template<> header + or in an inappropriate place. We've already given an error, so just + bail now so we don't actually define the specialization. */ + return error_mark_node; } else if (CLASS_TYPE_P (type) && !CLASSTYPE_USE_TEMPLATE (type) diff --git a/gcc/testsuite/g++.dg/template/crash105.C b/gcc/testsuite/g++.dg/template/crash105.C index 649bf8b..8cfff6a 100644 --- a/gcc/testsuite/g++.dg/template/crash105.C +++ b/gcc/testsuite/g++.dg/template/crash105.C @@ -10,5 +10,8 @@ template < typename > struct S < int > void f () { - S < int >::f (); // { dg-error "cannot call" } + S < int >::f (); } + +// Don't be picky about error-recovery. +// { dg-prune-output "." } diff --git a/gcc/testsuite/g++.dg/template/error48.C b/gcc/testsuite/g++.dg/template/error48.C new file mode 100644 index 0000000..483f7b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/error48.C @@ -0,0 +1,15 @@ +// PR c++/54416 + +template < typename T > struct foo; +template <> struct foo < int >; +template < typename T > struct bar +{ + template <> struct foo < int > // { dg-error "non-namespace scope" } + { + void baz (); + }; +}; +void foo < int >::baz () { } + +// Don't be picky about error-recovery. +// { dg-prune-output "." }