[gcc r15-10935] c++/modules: Allow merging members of instantiations attached to named modules [PR124431]

Nathaniel Shead nshead@gcc.gnu.org
Thu Mar 12 04:13:12 GMT 2026


https://gcc.gnu.org/g:c982903092f55dfb6d5e75b4961db6573388dc0b

commit r15-10935-gc982903092f55dfb6d5e75b4961db6573388dc0b
Author: Nathaniel Shead <nathanieloshead@gmail.com>
Date:   Wed Mar 11 23:21:02 2026 +1100

    c++/modules: Allow merging members of instantiations attached to named modules [PR124431]
    
    The crash in the linked PR occurs because we treat all entities attached
    to a (different) named module as being unmergeable, and so end up with
    two different FIELD_DECLs for the member of a type.
    
    But templates can be instantiated or specialised in any module, not just
    the module they originated from, but are still considered attached to
    that named module.  It seems that we already handle class-scope
    VAR_DECL, FUNCTION_DECL, TYPE_DECL, and TEMPLATE_DECL correctly by using
    a MK_decl_spec or MK_type_spec merge kind, but FIELD_DECLs and
    CONST_DECLs are not depended upon separately and so never get
    MK_template_mask specs.
    
    For these cases I think we can always rely on the container being
    accurate and having its fields already setup, so this patch fixes the
    issue by allowing non-unique merge kind for decls with a template
    specialisation container of code TYPE_DECL.
    
            PR c++/124431
    
    gcc/cp/ChangeLog:
    
            * module.cc (trees_in::key_mergeable): Allow merging members of
            template specialisations.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/merge-21_a.C: New test.
            * g++.dg/modules/merge-21_b.C: New test.
            * g++.dg/modules/merge-21_c.C: New test.
            * g++.dg/modules/merge-21_d.C: New test.
    
    Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
    Reviewed-by: Jason Merrill <jason@redhat.com>
    (cherry picked from commit 7b1a7720ef8a5f59e10c0f90211c75af91e42b90)

Diff:
---
 gcc/cp/module.cc                          |  6 +++++-
 gcc/testsuite/g++.dg/modules/merge-21_a.C | 16 ++++++++++++++++
 gcc/testsuite/g++.dg/modules/merge-21_b.C | 11 +++++++++++
 gcc/testsuite/g++.dg/modules/merge-21_c.C |  9 +++++++++
 gcc/testsuite/g++.dg/modules/merge-21_d.C | 20 ++++++++++++++++++++
 5 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 2b275260d1ed..d0a481849ff1 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11972,12 +11972,16 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
 
 	  case TYPE_DECL:
 	    gcc_checking_assert (!is_imported_temploid_friend);
+	    int use_tmpl = 0;
 	    if (is_attached && !(state->is_module () || state->is_partition ())
 		/* Implicit member functions can come from
 		   anywhere.  */
 		&& !(DECL_ARTIFICIAL (decl)
 		     && TREE_CODE (decl) == FUNCTION_DECL
-		     && !DECL_THUNK_P (decl)))
+		     && !DECL_THUNK_P (decl))
+		/* As can members of template specialisations.  */
+		&& !(node_template_info (container, use_tmpl)
+		     && use_tmpl != 0))
 	      kind = "unique";
 	    else
 	      {
diff --git a/gcc/testsuite/g++.dg/modules/merge-21_a.C b/gcc/testsuite/g++.dg/modules/merge-21_a.C
new file mode 100644
index 000000000000..77f47f544a2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-21_a.C
@@ -0,0 +1,16 @@
+// PR c++/124431
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi A }
+
+export module A;
+
+export template <int N> struct mat {
+  int data[1] = { 123 };
+  constexpr const int& operator[](int x) const { return data[x]; };
+};
+
+export template <int N> struct S {
+  int field;
+  enum e { a };
+  enum class ce { ca };
+};
diff --git a/gcc/testsuite/g++.dg/modules/merge-21_b.C b/gcc/testsuite/g++.dg/modules/merge-21_b.C
new file mode 100644
index 000000000000..5947f0bf6a3f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-21_b.C
@@ -0,0 +1,11 @@
+// PR c++/124431
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi B }
+
+export module B;
+export import A;
+struct X {
+  mat<4> viewmatrix;
+};
+
+template struct S<0>;
diff --git a/gcc/testsuite/g++.dg/modules/merge-21_c.C b/gcc/testsuite/g++.dg/modules/merge-21_c.C
new file mode 100644
index 000000000000..ebd39fb96718
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-21_c.C
@@ -0,0 +1,9 @@
+// PR c++/124431
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi C }
+
+export module C;
+export import A;
+mat<4> from_triangle_frame;
+
+template struct S<0>;
diff --git a/gcc/testsuite/g++.dg/modules/merge-21_d.C b/gcc/testsuite/g++.dg/modules/merge-21_d.C
new file mode 100644
index 000000000000..f34af1852786
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-21_d.C
@@ -0,0 +1,20 @@
+// PR c++/124431
+// { dg-additional-options "-fmodules -fdump-lang-module-alias" }
+
+import C;
+import B;
+
+void test() {
+  constexpr auto r = mat<4>()[0];
+  // { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) field_decl:'::mat@.:.<0x4>::data'} module } }
+
+  S<0> s;
+  s.field;
+  // { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) field_decl:'::S@.:.<0x0>::field'} module } }
+
+  S<0>::e se = S<0>::a;
+  // { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) const_decl:'::S@.:.<0x0>::e@.:.<0x0>::a'} module } }
+
+  S<0>::ce sce = S<0>::ce::ca;
+  // { dg-final { scan-lang-dump {Read:-[0-9]*'s named merge key \(matched\) const_decl:'::S@.:.<0x0>::ce@.:.<0x0>::ca'} module } }
+}


More information about the Gcc-cvs mailing list