Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

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.
---
 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(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-11_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/friend-11_b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5e8d1c9644c..c6e284d060c 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 5f990ea56b2..29165e447b3 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 014af618088..e0afc1728ac 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 ccabd640757..1578674614e 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 bbbf49363e8..b10442b0960 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 00000000000..2382f4c4898
--- /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 00000000000..e8baeee66c9
--- /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>>();
+}

base-commit: 05a3346353dce270d8b6ef0d13fe977cf75d1fcb
-- 
2.51.0

Reply via email to