Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/16? Thought I'd submit a patch even though the fix isn't perfect
or fully understood (to me).
-- >8 --
Jason's analysis: Here the issue here seems to be that
1) we don't add op==<__ni<int>,__ni<int>> as a pending specialization to
any key, so we don't load it until we see the use of it in foo(), at
which point we've already created another decl for it. And then
2) we fail to merge the loaded specialization with the existing one.
If op== were a member template instead of a hidden friend, we'd get
Pending specialization '::__normal_iterator<int>::template operator==<_Iter>'
entity:4 section:2 also keyed to '::__normal_iterator'
Pending specialization
'::__normal_iterator<int>::operator==<::__normal_iterator<int>>' entity:7
section:3 keyed to '::__normal_iterator'
This lack seems to be because add_specializations completely ignores
friends; the existing code is clearly wrong, as it calls
template_args_equal to compare template arguments to a template rather
than another set of template arguments.
This patch partially corrects the is_friend code path treat to full
template friend instantiations as ordinary specializations, recording
them, while continuing to skip partial template friend instantiations.
The condition TI_TEMPLATE (ti) != entry->tmpl isn't perfect because for
consistency we probably also want to clear is_friend for instantiations
of a non-template friend of a class template, for which we'd need something
like TREE_CODE (spec) != TEMPLATE_DECL, but doing so seems to breaks the
augmented friend-13.C testcase below. Still, this seems to be a strict
improvement over the current buggy code which skips all friend
specializations.
PR c++/125555
gcc/cp/ChangeLog:
* module.cc (depset::hash::add_specializations): Refine
is_friend logic to clear the flag for full template friend
instantiations.
gcc/testsuite/ChangeLog:
* g++.dg/modules/friend-13.C: Also test instantiations of a
non-template friend of a
* g++.dg/modules/friend-14_a.H: New test.
* g++.dg/modules/friend-14_b.C: New test.
---
gcc/cp/module.cc | 12 ++++++++++--
gcc/testsuite/g++.dg/modules/friend-13.C | 1 +
gcc/testsuite/g++.dg/modules/friend-14_a.H | 14 ++++++++++++++
gcc/testsuite/g++.dg/modules/friend-14_b.C | 10 ++++++++++
4 files changed, 35 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/modules/friend-14_a.H
create mode 100644 gcc/testsuite/g++.dg/modules/friend-14_b.C
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e61cd700d8fb..03a67ed25365 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -15478,8 +15478,16 @@ depset::hash::add_specializations (bool decl_p)
}
else if (is_friend)
{
- if (TI_TEMPLATE (ti) != entry->tmpl
- || !template_args_equal (TI_ARGS (ti), entry->tmpl))
+ if (TI_TEMPLATE (ti) != entry->tmpl)
+ /* This is a full instantiation of a template friend (of a
+ class template), treat it as an ordinary specialization
+ (PR125555). */
+ is_friend = false;
+ else
+ /* A partial instantiation of such a template friend, or an
+ instantiation of a non-template friend (of a class
+ template). FIXME we probably should clear is_friend in
+ the latter case too but that breaks friend-13.C. */
goto template_friend;
}
}
diff --git a/gcc/testsuite/g++.dg/modules/friend-13.C
b/gcc/testsuite/g++.dg/modules/friend-13.C
index 8930eca7ded5..f9fd8e366470 100644
--- a/gcc/testsuite/g++.dg/modules/friend-13.C
+++ b/gcc/testsuite/g++.dg/modules/friend-13.C
@@ -5,6 +5,7 @@
module;
template <typename T> struct tuple {
template <typename U> friend void f(tuple, U);
+ friend void g(tuple, int) { }
};
template <typename T> tuple<T> make_unique();
export module M;
diff --git a/gcc/testsuite/g++.dg/modules/friend-14_a.H
b/gcc/testsuite/g++.dg/modules/friend-14_a.H
new file mode 100644
index 000000000000..b303f5cccc5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-14_a.H
@@ -0,0 +1,14 @@
+// PR c++/125555
+// { dg-additional-options "-fmodule-header" }
+
+template<typename _Tp>
+struct __normal_iterator {
+ template <typename _Iter>
+ friend bool operator==(__normal_iterator, _Iter) { return true; }
+};
+
+template <typename _Up>
+void foo() {
+ __normal_iterator<int> it;
+ it == it;
+}
diff --git a/gcc/testsuite/g++.dg/modules/friend-14_b.C
b/gcc/testsuite/g++.dg/modules/friend-14_b.C
new file mode 100644
index 000000000000..94189e5cc88a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/friend-14_b.C
@@ -0,0 +1,10 @@
+// PR c++/125555
+// { dg-additional-options "-fmodules" }
+
+import "friend-14_a.H";
+
+void test() {
+ __normal_iterator<int> it;
+ it == it;
+ foo<void>();
+}
--
2.55.0.787.g3cb9185f65