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
This commit is contained in:
parent
5c95b82b61
commit
26b81a446f
|
@ -1,3 +1,11 @@
|
|||
2019-03-30 Jason Merrill <jason@redhat.com>
|
||||
|
||||
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 <jakub@redhat.com>
|
||||
|
||||
PR sanitizer/89869
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
14
gcc/cp/pt.c
14
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;
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue