diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-10-31 20:05:16 +1100 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-11-02 22:16:30 +1100 |
commit | 815e48e3d42231b675bae1dec5fa26890f048ef1 (patch) | |
tree | 01e458c5a34330f09271ef67f14410ac0266237d | |
parent | 4a99443c5dd9a235022652ba0fb143c6370ea99d (diff) | |
download | gcc-815e48e3d42231b675bae1dec5fa26890f048ef1.zip gcc-815e48e3d42231b675bae1dec5fa26890f048ef1.tar.gz gcc-815e48e3d42231b675bae1dec5fa26890f048ef1.tar.bz2 |
c++/modules: Propagate TYPE_CANONICAL for partial specialisations [PR113814]
In some cases, when we go to import a partial specialisation there might
already be an incomplete implicit instantiation in the specialisation
table. This causes ICEs described in the linked PR as we now have two
separate matching specialisations for this same arguments with different
TYPE_CANONICAL.
We already support multiple specialisations with the same args however,
as they may be differently constrained. So we can solve this by simply
ensuring that the TYPE_CANONICAL of the new partial specialisation
matches the existing specialisation.
PR c++/113814
gcc/cp/ChangeLog:
* pt.cc (add_mergeable_specialization): Propagate
TYPE_CANONICAL.
gcc/testsuite/ChangeLog:
* g++.dg/modules/partial-6.h: New test.
* g++.dg/modules/partial-6_a.H: New test.
* g++.dg/modules/partial-6_b.H: New test.
* g++.dg/modules/partial-6_c.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Co-authored-by: Jason Merrill <jason@redhat.com>
-rw-r--r-- | gcc/cp/pt.cc | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/partial-6.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/partial-6_a.H | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/partial-6_b.H | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/partial-6_c.C | 12 |
5 files changed, 60 insertions, 5 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 334dbb3..f4213f8 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -31731,12 +31731,16 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl, auto *slot = type_specializations->find_slot (elt, INSERT); /* We don't distinguish different constrained partial type - specializations, so there could be duplicates. Everything else - must be new. */ - if (!(flags & 2 && *slot)) + specializations, so there could be duplicates. In that case we + must propagate TYPE_CANONICAL so that they are treated as the + same type. Everything else must be new. */ + if (*slot) + { + gcc_checking_assert (flags & 2); + TYPE_CANONICAL (elt->spec) = TYPE_CANONICAL ((*slot)->spec); + } + else { - gcc_checking_assert (!*slot); - auto entry = ggc_alloc<spec_entry> (); *entry = *elt; *slot = entry; diff --git a/gcc/testsuite/g++.dg/modules/partial-6.h b/gcc/testsuite/g++.dg/modules/partial-6.h new file mode 100644 index 0000000..702c9a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-6.h @@ -0,0 +1,7 @@ +// PR c++/113814 + +template <typename> struct A {}; +template <typename T> A<T*> f(); + +template <template <typename> typename, typename> struct B; +template <template <typename> typename TT> B<TT, int> g(); diff --git a/gcc/testsuite/g++.dg/modules/partial-6_a.H b/gcc/testsuite/g++.dg/modules/partial-6_a.H new file mode 100644 index 0000000..6e0d5dd --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-6_a.H @@ -0,0 +1,11 @@ +// PR c++/113814 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "partial-6.h" + +template <typename T> +struct A<T*> { int a; }; + +template <template <typename> typename TT> +struct B<TT, int> { int b; }; diff --git a/gcc/testsuite/g++.dg/modules/partial-6_b.H b/gcc/testsuite/g++.dg/modules/partial-6_b.H new file mode 100644 index 0000000..569959b --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-6_b.H @@ -0,0 +1,21 @@ +// PR c++/113814 +// { dg-additional-options "-fmodules-ts -fdump-lang-module-alias" } +// { dg-module-cmi {} } + +#include "partial-6.h" +import "partial-6_a.H"; + +template <typename, typename = void> +struct TestTTP; + +inline void test() { + int a = f<int>().a; + int b = g<TestTTP>().b; +} + +// { dg-final { scan-lang-dump {Read:-[0-9]*'s partial merge key \(new\) template_decl:'::template A'} module } } +// { dg-final { scan-lang-dump {Read:-[0-9]*'s partial merge key \(new\) template_decl:'::template B'} module } } + +// Don't need to write the partial specialisations +// { dg-final { scan-lang-dump-not {Wrote declaration entity:[0-9]* template_decl:'::template A<#null#>'} module } } +// { dg-final { scan-lang-dump-not {Wrote declaration entity:[0-9]* template_decl:'::template B<template TT,int>'} module } } diff --git a/gcc/testsuite/g++.dg/modules/partial-6_c.C b/gcc/testsuite/g++.dg/modules/partial-6_c.C new file mode 100644 index 0000000..2a34457 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-6_c.C @@ -0,0 +1,12 @@ +// PR c++/113814 +// { dg-additional-options "-fmodules-ts" } + +import "partial-6_b.H"; + +template <typename> +struct TestTTP2; + +int main() { + int a = f<double>().a; + int b = g<TestTTP2>().b; +} |