aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-01-29 15:44:50 -0500
committerJason Merrill <jason@gcc.gnu.org>2014-01-29 15:44:50 -0500
commit7651c656858e4c80febb67e1742c0aa0d716e1a1 (patch)
treef24433780390756fc9922334753b790abea23c6e /gcc
parentd530142ddb708112ad0a7dabaf74f9b4072fa120 (diff)
downloadgcc-7651c656858e4c80febb67e1742c0aa0d716e1a1.zip
gcc-7651c656858e4c80febb67e1742c0aa0d716e1a1.tar.gz
gcc-7651c656858e4c80febb67e1742c0aa0d716e1a1.tar.bz2
re PR c++/59956 (internal compiler error: unexpected expression ‘P_S’ of kind template_parm_index)
PR c++/59956 * friend.c (do_friend): Pass the TEMPLATE_DECL to add_friend if we have a friend template in a class template. * pt.c (tsubst_friend_function): Look through it. (push_template_decl_real): A friend member template is primary. From-SVN: r207281
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/friend.c8
-rw-r--r--gcc/cp/pt.c14
-rw-r--r--gcc/testsuite/g++.dg/template/friend55.C18
4 files changed, 45 insertions, 4 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3215a43..723ce95 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,12 @@
+2014-01-29 Jason Merrill <jason@redhat.com>
+
+ PR c++/59956
+ * friend.c (do_friend): Pass the TEMPLATE_DECL to add_friend if we
+ have a friend template in a class template.
+ * pt.c (tsubst_friend_function): Look through it.
+ (push_template_decl_real): A friend member template is
+ primary.
+
2014-01-29 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/58846
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 4fd6ffa..150b392 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -501,7 +501,13 @@ do_friend (tree ctype, tree declarator, tree decl,
? current_template_parms
: NULL_TREE);
- if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
+ if ((template_member_p
+ /* Always pull out the TEMPLATE_DECL if we have a friend
+ template in a class template so that it gets tsubsted
+ properly later on (59956). tsubst_friend_function knows
+ how to tell this apart from a member template. */
+ || (class_template_depth && friend_depth))
+ && decl && TREE_CODE (decl) == FUNCTION_DECL)
decl = DECL_TI_TEMPLATE (decl);
if (decl)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ce679f6..943255d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4615,7 +4615,8 @@ push_template_decl_real (tree decl, bool is_friend)
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
/* See if this is a primary template. */
- if (is_friend && ctx)
+ if (is_friend && ctx
+ && uses_template_parms_level (ctx, processing_template_decl))
/* A friend template that specifies a class context, i.e.
template <typename T> friend void A<T>::f();
is not primary. */
@@ -8424,10 +8425,17 @@ tsubst_friend_function (tree decl, tree args)
if (COMPLETE_TYPE_P (context))
{
+ tree fn = new_friend;
+ /* do_friend adds the TEMPLATE_DECL for any member friend
+ template even if it isn't a member template, i.e.
+ template <class T> friend A<T>::f();
+ Look through it in that case. */
+ if (TREE_CODE (fn) == TEMPLATE_DECL
+ && !PRIMARY_TEMPLATE_P (fn))
+ fn = DECL_TEMPLATE_RESULT (fn);
/* Check to see that the declaration is really present, and,
possibly obtain an improved declaration. */
- tree fn = check_classfn (context,
- new_friend, NULL_TREE);
+ fn = check_classfn (context, fn, NULL_TREE);
if (fn)
new_friend = fn;
diff --git a/gcc/testsuite/g++.dg/template/friend55.C b/gcc/testsuite/g++.dg/template/friend55.C
new file mode 100644
index 0000000..4abe6ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend55.C
@@ -0,0 +1,18 @@
+// PR c++/59956
+
+template <int I> struct A;
+template <int I> class B {
+ int i;
+ template <int A_S> friend void A<A_S>::impl();
+};
+
+B<0> b1;
+template<int I>struct A { void impl(); };
+B<1> b2;
+
+template<int I> void A<I>::impl() { ++b1.i; ++b2.i; }
+
+int main()
+{
+ A<0>().impl();
+}