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.
Tested x86_64-pc-linux-gnu, applying to trunk.
* pt.c (lookup_template_class_1): If the partial instantiation is
explicitly specialized, adjust.
(maybe_process_partial_specialization): Also adjust
CLASSTYPE_TI_ARGS.
---
gcc/cp/cp-tree.h | 10 +++-
gcc/cp/pt.c | 14 ++++-
gcc/testsuite/g++.dg/template/mem-spec1.C | 68 +++++++++++++++++++++++
gcc/cp/ChangeLog | 8 +++
4 files changed, 98 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/mem-spec1.C
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 <typename T> struct S {};
template <typename T> struct S<T*> {};
- the CLASSTPYE_TI_TEMPLATE for S<int*> will be S, not the S<T*>. */
+ the CLASSTPYE_TI_TEMPLATE for S<int*> will be S, not the S<T*>.
+
+ 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 T> class C { template <class U> class D; }
+ template <> template <class U> class C<int>::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<spec_entry> ();
*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<typename> struct A
+ {
+ template<typename> struct B {};
+ A() { B<int> b; }
+ };
+
+ template<> template<typename>
+ struct A<int>::B
+ {
+ virtual void foo() {}
+ };
+
+ A<int> a;
+}
+
+namespace N2 {
+ template<typename> struct A
+ {
+ template<typename> struct B {};
+ A() { B<int> b; }
+ };
+
+ template<> template<typename>
+ struct A<int>::B
+ {
+ virtual void foo() {}
+ void bar() {}
+ };
+
+ A<int> a;
+}
+
+namespace N3 {
+ template<typename> struct A
+ {
+ template<typename> struct B {};
+ A() { B<int> b; }
+ };
+
+ template<> template<typename>
+ struct A<int>::B
+ {
+ ~B() {}
+ };
+
+ A<int> a;
+}
+
+#if __cpp_variadic_templates
+namespace N4 {
+ template<typename...> struct A
+ {
+ template<typename> struct B {};
+ typedef B<int> X;
+ };
+
+ template<> template<typename>
+ struct A<int>::B
+ {
+ typedef int Y;
+ };
+
+ A<int>::B<int> b;
+}
+#endif
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 <[email protected]>
+
+ 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 <[email protected]>
PR sanitizer/89869
base-commit: 6480ce44627df7aa01f5257a952b3e0f6b438ed7
--
2.20.1