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