]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/modules: Propagate TYPE_CANONICAL for partial specialisations [PR113814]
authorNathaniel Shead <nathanieloshead@gmail.com>
Thu, 31 Oct 2024 09:05:16 +0000 (20:05 +1100)
committerNathaniel Shead <nathanieloshead@gmail.com>
Sat, 2 Nov 2024 11:16:30 +0000 (22:16 +1100)
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>
gcc/cp/pt.cc
gcc/testsuite/g++.dg/modules/partial-6.h [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/partial-6_a.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/partial-6_b.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/partial-6_c.C [new file with mode: 0644]

index 334dbb3c39aaa7ed356713bd0390f2909599fca4..f4213f88b99f4ca60f2507b2aa6440786e1a8587 100644 (file)
@@ -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 (file)
index 0000000..702c9a1
--- /dev/null
@@ -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 (file)
index 0000000..6e0d5dd
--- /dev/null
@@ -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 (file)
index 0000000..569959b
--- /dev/null
@@ -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 (file)
index 0000000..2a34457
--- /dev/null
@@ -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;
+}