aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2024-08-06 15:41:38 +1000
committerNathaniel Shead <nathanieloshead@gmail.com>2024-08-08 16:03:10 +1000
commit79209273663672ff05663554741fd2558b4aac99 (patch)
treee338682e68405f3cc370d373d1ad71b62efd9f3f /gcc
parentc592310d5275e09977504c136419686bd2277af0 (diff)
downloadgcc-79209273663672ff05663554741fd2558b4aac99.zip
gcc-79209273663672ff05663554741fd2558b4aac99.tar.gz
gcc-79209273663672ff05663554741fd2558b4aac99.tar.bz2
c++/modules: Handle instantiating already tsubsted template friend classes [PR115801]
With modules it may be the case that a template friend class provided with a qualified name is not found by name lookup at instantiation time, due to the class not being exported from its module. This causes issues in tsubst_friend_class which did not handle this case. This is caused by the named friend class not actually requiring tsubsting. This was already worked around for the "found by name lookup" case (g++.dg/template/friend5.C), but it looks like there's no need to do name lookup at all for this particular case to work. We do need to be careful to continue to do name lookup to handle templates from an outer current instantiation though; this patch adds a new testcase for this as well. This should not impact modules (because exportingness will only affect namespace lookup). PR c++/115801 gcc/cp/ChangeLog: * pt.cc (tsubst_friend_class): Return the type immediately when no tsubsting or name lookup is required. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-16_a.C: New test. * g++.dg/modules/tpl-friend-16_b.C: New test. * g++.dg/template/friend82.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> Reviewed-by: Patrick Palka <ppalka@redhat.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc8
-rw-r--r--gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C40
-rw-r--r--gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C17
-rw-r--r--gcc/testsuite/g++.dg/template/friend82.C23
4 files changed, 88 insertions, 0 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3e55d5c..1dde7d1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11732,6 +11732,14 @@ tsubst_friend_class (tree friend_tmpl, tree args)
return TREE_TYPE (tmpl);
}
+ if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl)) == 1)
+ /* The template has already been fully substituted, e.g. for
+
+ template <typename> friend class ::C;
+
+ so we can just return it directly. */
+ return TREE_TYPE (friend_tmpl);
+
tree context = CP_DECL_CONTEXT (friend_tmpl);
if (TREE_CODE (context) == NAMESPACE_DECL)
push_nested_namespace (context);
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C
new file mode 100644
index 0000000..e1cdcd9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C
@@ -0,0 +1,40 @@
+// PR c++/115801
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi test }
+
+module;
+
+template <typename T> struct GMF;
+template <typename T> struct GMF_Hidden {
+ int go() { GMF<T> gmf; return gmf.x; }
+};
+
+template <typename T> struct GMF {
+private:
+ template <typename> friend struct ::GMF_Hidden;
+ int x = 1;
+};
+
+template <typename T> int test_gmf() {
+ GMF_Hidden<T> h; return h.go();
+}
+
+export module test;
+
+export using ::GMF;
+export using ::test_gmf;
+
+export template <typename> struct Attached;
+template <typename T> struct Attached_Hidden {
+ int go() { Attached<T> attached; return attached.x; }
+};
+
+template <typename T> struct Attached {
+private:
+ template <typename> friend struct ::Attached_Hidden;
+ int x = 2;
+};
+
+export template <typename T> int test_attached() {
+ Attached_Hidden<T> h; return h.go();
+}
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C
new file mode 100644
index 0000000..d3484ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C
@@ -0,0 +1,17 @@
+// PR c++/115801
+// { dg-additional-options "-fmodules-ts" }
+
+import test;
+
+int main() {
+ GMF<int> gmf;
+ Attached<int> attached;
+
+ int a = test_gmf<double>();
+ int b = test_attached<double>();
+
+ GMF_Hidden<int> gmf_hidden; // { dg-error "not declared" }
+ Attached_Hidden<int> attached_hidden; // { dg-error "not declared" }
+}
+
+// { dg-prune-output "expected primary-expression" }
diff --git a/gcc/testsuite/g++.dg/template/friend82.C b/gcc/testsuite/g++.dg/template/friend82.C
new file mode 100644
index 0000000..28a057d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend82.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+template<class T>
+struct A {
+ template<class U> struct B;
+
+ template<class U>
+ struct C {
+ template<class V> friend struct A::B;
+ private:
+ int x;
+ };
+};
+
+template <class T>
+template <class U>
+struct A<T>::B {
+ int foo(A<int*>::C<long> c) { return c.x; } // { dg-error "private" }
+};
+
+template struct A<int*>::C<long>;
+template struct A<int*>::B<long>; // { dg-bogus "" }
+template struct A<double*>::B<long>; // { dg-message "required from here" }