]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/modules: Stream DECL_CHAIN for decl_specialization_friend_p functions
authorNathaniel Shead <nathanieloshead@gmail.com>
Mon, 1 Dec 2025 13:43:18 +0000 (00:43 +1100)
committerNathaniel Shead <nathanieloshead@gmail.com>
Mon, 1 Dec 2025 23:12:09 +0000 (10:12 +1100)
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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/friend-12_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/friend-12_b.C [new file with mode: 0644]

index 91e305c280b79a37eb50eb06740018207e8e94d0..042b029a036eed476466a32c6de1ae58449fff96 100644 (file)
@@ -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 (file)
index 0000000..827c74b
--- /dev/null
@@ -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 (file)
index 0000000..7eb7014
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules -Wno-global-module" }
+// { dg-module-cmi M }
+
+export module M;
+export import :part;