Skip to content
Snippets Groups Projects
Commit 79209273 authored by Nathaniel Shead's avatar Nathaniel Shead
Browse files

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: default avatarNathaniel Shead <nathanieloshead@gmail.com>
Reviewed-by: default avatarPatrick Palka <ppalka@redhat.com>
Reviewed-by: default avatarJason Merrill <jason@redhat.com>
parent c592310d
No related branches found
No related tags found
No related merge requests found
......@@ -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);
......
// 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();
}
// 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" }
// { 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" }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment