From 26b81a446f6e333bb5e80d40eb467260948ee79e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 30 Mar 2019 11:23:37 -0400 Subject: [PATCH] PR c++/89744 - ICE with specialization of member class template. My fix five years ago for PR 60241 was incomplete: when we reassign implicit instances of a partial instantiation of a member template to the explicit specialization of that partial instantiation, we also need to adjust the CLASSTYPE_TI_ARGS to match what we'd get when looking up that instance after the explicit specialization. We also need to do this when we later look up the instance in a way that only finds the explicit specialization halfway through lookup_template_class_1. * pt.c (lookup_template_class_1): If the partial instantiation is explicitly specialized, adjust. (maybe_process_partial_specialization): Also adjust CLASSTYPE_TI_ARGS. From-SVN: r270036 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/cp-tree.h | 10 +++- gcc/cp/pt.c | 14 ++++- gcc/testsuite/g++.dg/template/mem-spec1.C | 68 +++++++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/mem-spec1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a31e4391e21..8a5e9209b34 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2019-03-30 Jason Merrill + + PR c++/89744 - ICE with specialization of member class template. + * pt.c (lookup_template_class_1): If the partial instantiation is + explicitly specialized, adjust. + (maybe_process_partial_specialization): Also adjust + CLASSTYPE_TI_ARGS. + 2019-03-29 Jakub Jelinek PR sanitizer/89869 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fd612b0dbb1..59152753825 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3534,7 +3534,15 @@ struct GTY(()) lang_decl { template struct S {}; template struct S {}; - the CLASSTPYE_TI_TEMPLATE for S will be S, not the S. */ + the CLASSTPYE_TI_TEMPLATE for S will be S, not the S. + + For a member class template, CLASSTYPE_TI_TEMPLATE always refers to the + partial instantiation rather than the primary template. CLASSTYPE_TI_ARGS + are for the primary template if the partial instantiation isn't + specialized, or for the explicit specialization if it is, e.g. + + template class C { template class D; } + template <> template class C::D; */ #define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE)) #define CLASSTYPE_TI_ARGS(NODE) TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 91c341589be..f3faa89f671 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1090,7 +1090,8 @@ maybe_process_partial_specialization (tree type) type_specializations->remove_elt (&elt); elt.tmpl = tmpl; - elt.args = INNERMOST_TEMPLATE_ARGS (elt.args); + CLASSTYPE_TI_ARGS (inst) + = elt.args = INNERMOST_TEMPLATE_ARGS (elt.args); spec_entry **slot = type_specializations->find_slot (&elt, INSERT); @@ -9662,6 +9663,16 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, : (TREE_CODE (found) == TYPE_DECL ? DECL_TI_TEMPLATE (found) : CLASSTYPE_TI_TEMPLATE (found))); + + if (DECL_CLASS_TEMPLATE_P (found) + && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found))) + { + /* If this partial instantiation is specialized, we want to + use it for hash table lookup. */ + elt.tmpl = found; + elt.args = arglist = INNERMOST_TEMPLATE_ARGS (arglist); + hash = spec_hasher::hash (&elt); + } } // Build template info for the new specialization. @@ -9669,6 +9680,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, elt.spec = t; slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT); + gcc_checking_assert (*slot == NULL); entry = ggc_alloc (); *entry = elt; *slot = entry; diff --git a/gcc/testsuite/g++.dg/template/mem-spec1.C b/gcc/testsuite/g++.dg/template/mem-spec1.C new file mode 100644 index 00000000000..b06df0aa84e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/mem-spec1.C @@ -0,0 +1,68 @@ +// PR c++/89744 + +namespace N1 { + template struct A + { + template struct B {}; + A() { B b; } + }; + + template<> template + struct A::B + { + virtual void foo() {} + }; + + A a; +} + +namespace N2 { + template struct A + { + template struct B {}; + A() { B b; } + }; + + template<> template + struct A::B + { + virtual void foo() {} + void bar() {} + }; + + A a; +} + +namespace N3 { + template struct A + { + template struct B {}; + A() { B b; } + }; + + template<> template + struct A::B + { + ~B() {} + }; + + A a; +} + +#if __cpp_variadic_templates +namespace N4 { + template struct A + { + template struct B {}; + typedef B X; + }; + + template<> template + struct A::B + { + typedef int Y; + }; + + A::B b; +} +#endif -- 2.30.2