On 12/1/25 7:18 PM, Nathaniel Shead wrote:
I bumped into this while reducing a different issue.  Bootstrapped and
tested (so far just modules.exp) on x86_64-pc-linux-gnu, OK for trunk if
full regtest passes?

OK.
-- >8 --

r16-5298 attached the owning class for a friend template specialisation
on its DECL_CHAIN.  However we don't stream DECL_CHAIN in general to
avoid walking into unrelated entities on the scope chain; this patch
adds a special case for these functions to ensure we don't lose this
information.

Ideally this would occur in trees_{out,in}::core_vals, but we can't
check decl_specialization_friend_p until after DECL_TEMPLATE_INFO has
been streamed, hence the slightly unusual placement.

gcc/cp/ChangeLog:

        * module.cc (trees_out::lang_decl_vals): Stream DECL_CHAIN for
        decl_specialization_friend_p functions.
        (trees_in::lang_decl_vals): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/friend-12_a.C: New test.
        * g++.dg/modules/friend-12_b.C: New test.

Signed-off-by: Nathaniel Shead <[email protected]>
---
  gcc/cp/module.cc                           |  8 ++++++++
  gcc/testsuite/g++.dg/modules/friend-12_a.C | 11 +++++++++++
  gcc/testsuite/g++.dg/modules/friend-12_b.C |  5 +++++
  3 files changed, 24 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/modules/friend-12_a.C
  create mode 100644 gcc/testsuite/g++.dg/modules/friend-12_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e5668be4786..cae45224c9e 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -7524,6 +7524,12 @@ trees_out::lang_decl_vals (tree t)
WT (access);
        }
+      /* A friend template specialisation stashes its owning class on its
+        DECL_CHAIN; we need to reconstruct this, but it needs to happen
+        after we stream the template_info so readers can know this is such
+        an entity.  */
+      if (decl_specialization_friend_p (t))
+       WT (t->common.chain);
        break;
case lds_ns: /* lang_decl_ns. */
@@ -7593,6 +7599,8 @@ trees_in::lang_decl_vals (tree t)
      lds_min:
        RT (lang->u.min.template_info);
        RT (lang->u.min.access);
+      if (decl_specialization_friend_p (t))
+       RT (t->common.chain);
        break;
case lds_ns: /* lang_decl_ns. */
diff --git a/gcc/testsuite/g++.dg/modules/friend-12_a.C 
b/gcc/testsuite/g++.dg/modules/friend-12_a.C
new file mode 100644
index 00000000000..827c74b8f58
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-12_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules -Wno-global-module" }
+// { dg-module-cmi M:part }
+
+module;
+template <typename T> struct basic_streambuf;
+template <typename T> void __copy_streambufs_eof(basic_streambuf<T>*);
+template <typename T> struct basic_streambuf {
+  friend void __copy_streambufs_eof<>(basic_streambuf*);
+};
+export module M:part;
+void foo(basic_streambuf<char>&) {}
diff --git a/gcc/testsuite/g++.dg/modules/friend-12_b.C 
b/gcc/testsuite/g++.dg/modules/friend-12_b.C
new file mode 100644
index 00000000000..7eb7014660f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-12_b.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules -Wno-global-module" }
+// { dg-module-cmi M }
+
+export module M;
+export import :part;

Reply via email to