https://gcc.gnu.org/g:2359344af53a5fc844d108fcf9f0e8bddd84a6b5

commit r16-5298-g2359344af53a5fc844d108fcf9f0e8bddd84a6b5
Author: Jason Merrill <[email protected]>
Date:   Wed Nov 12 15:03:46 2025 +0530

    c++/modules: friend void foo<bar>()
    
    23_containers/mdspan/layouts/padded.cc was failing because on load we were
    wrongly treating the __get_static_stride friends as equivalent between
    layout_left_padded and layout_right_padded.  This happened because we were
    wrongly pushing these declarations into namespace scope even though we don't
    yet know what template they instantiate.  Fixed by using the same
    MK_local_friend mechanism as template friends.
    
    gcc/cp/ChangeLog:
    
            * decl.cc (grokfndecl): Set DECL_CHAIN of a friend f<>.
            * module.cc (trees_out::get_merge_kind): Give it MK_local_friend.
            (trees_out::decl_container): Its container is the befriender.
            (trees_out::key_mergeable): Expand comment.
            * cp-tree.h (decl_specialization_friend_p): New.
            * friend.cc (do_friend): Use it.
            * pt.cc (tsubst_friend_function): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/friend-11_a.C: New test.
            * g++.dg/modules/friend-11_b.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                           | 12 ++++++++++++
 gcc/cp/decl.cc                             |  5 +++++
 gcc/cp/friend.cc                           |  4 ++--
 gcc/cp/module.cc                           |  9 ++++++---
 gcc/cp/pt.cc                               |  4 +---
 gcc/testsuite/g++.dg/modules/friend-11_a.C | 22 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/modules/friend-11_b.C |  9 +++++++++
 7 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5e8d1c9644c5..c6e284d060ca 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7658,6 +7658,18 @@ extern tree implicitly_declare_fn               
(special_function_kind, tree,
                                                 bool, tree, tree);
 extern tree type_order_value                   (tree, tree);
 
+/* True iff DECL represents a declaration of a friend template
+   specialization, e.g. friend void f<>().  */
+
+inline bool
+decl_specialization_friend_p (tree decl)
+{
+  return (TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_UNIQUE_FRIEND_P (decl)
+         && DECL_IMPLICIT_INSTANTIATION (decl)
+         && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL);
+}
+
 /* In module.cc  */
 class module_state; /* Forward declare.  */
 inline bool modules_p () { return flag_modules != 0; }
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 5f990ea56b2c..29165e447b38 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -12097,6 +12097,11 @@ grokfndecl (tree ctype,
          gcc_assert (identifier_p (fns) || OVL_P (fns));
          DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args);
 
+         /* Remember the befriending class like push_template_decl does for
+            template friends.  */
+         gcc_checking_assert (!DECL_CHAIN (decl));
+         DECL_CHAIN (decl) = current_scope ();
+
          for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
            if (TREE_PURPOSE (t)
                && TREE_CODE (TREE_PURPOSE (t)) == DEFERRED_PARSE)
diff --git a/gcc/cp/friend.cc b/gcc/cp/friend.cc
index 014af618088c..e0afc1728ac6 100644
--- a/gcc/cp/friend.cc
+++ b/gcc/cp/friend.cc
@@ -662,8 +662,8 @@ do_friend (tree scope, tree declarator, tree decl,
   if (decl == error_mark_node)
     return error_mark_node;
 
-  if (!class_template_depth && DECL_IMPLICIT_INSTANTIATION (decl)
-      && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+  if (!class_template_depth
+      && decl_specialization_friend_p (decl))
     /* "[if no non-template match is found,] each remaining function template
        is replaced with the specialization chosen by deduction from the
        friend declaration or discarded if deduction fails."
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ccabd640757d..1578674614e7 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11492,7 +11492,8 @@ trees_out::get_merge_kind (tree decl, depset *dep)
              }
 
            if (TREE_CODE (decl) == TEMPLATE_DECL
-               && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
+               ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)
+               : decl_specialization_friend_p (decl))
              {
                mk = MK_local_friend;
                break;
@@ -11568,7 +11569,8 @@ trees_out::decl_container (tree decl)
 
   tree container = NULL_TREE;
   if (TREE_CODE (decl) == TEMPLATE_DECL
-      && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
+      ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)
+      : decl_specialization_friend_p (decl))
     container = DECL_CHAIN (decl);
   else
     container = CP_DECL_CONTEXT (decl);
@@ -11751,7 +11753,8 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree 
decl, tree inner,
 
        case MK_local_friend:
          {
-           /* Find by index on the class's DECL_LIST  */
+           /* Find by index on the class's DECL_LIST.  We set TREE_CHAIN to
+              point to the class in push_template_decl or grokfndecl.  */
            unsigned ix = 0;
            for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl));
                 decls; decls = TREE_CHAIN (decls))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bbbf49363e8f..b10442b09609 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11660,9 +11660,7 @@ tsubst_friend_function (tree decl, tree args)
 {
   tree new_friend;
 
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && DECL_TEMPLATE_INSTANTIATION (decl)
-      && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+  if (decl_specialization_friend_p (decl))
     /* This was a friend declared with an explicit template
        argument list, e.g.:
 
diff --git a/gcc/testsuite/g++.dg/modules/friend-11_a.C 
b/gcc/testsuite/g++.dg/modules/friend-11_a.C
new file mode 100644
index 000000000000..2382f4c4898a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-11_a.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-fmodules" }
+
+export module M;
+
+export {
+template <class T>
+int fn() {
+  return T::mem;
+}
+
+template <class T>
+class A {
+  inline static int mem = 42;
+  friend int fn<A>();
+};
+
+template <class T>
+class B {
+  inline static int mem = 24;
+  friend int fn<B>();
+};
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-11_b.C 
b/gcc/testsuite/g++.dg/modules/friend-11_b.C
new file mode 100644
index 000000000000..e8baeee66c92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-11_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules" }
+
+import M;
+
+int main()
+{
+  fn<A<int>>();
+  fn<B<int>>();
+}

Reply via email to