]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/59956 (internal compiler error: unexpected expression ‘P_S’ of kind templat...
authorJason Merrill <jason@redhat.com>
Fri, 1 Aug 2014 18:33:47 +0000 (14:33 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 1 Aug 2014 18:33:47 +0000 (14:33 -0400)
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: r213501

gcc/cp/ChangeLog
gcc/cp/friend.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/template/friend55.C [new file with mode: 0644]

index 9c49b5c669382a6b75865fc2ddc369f55253f2d9..7f01858ab6cc1ec0cb36ab308598894d21961c1c 100644 (file)
@@ -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-02-21  Jason Merrill  <jason@redhat.com>
 
        PR c++/60241
index 083372849b93d3896e3da67e1cb541bcce8c0c68..d0fe981ebbb41571cc24c55a5e38ad2f2126f48d 100644 (file)
@@ -502,7 +502,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)
index a8e2cd90fce9299b168efc747fdfca193b484e49..c03af2e93e0883d5d8ecf548681246702c91a575 100644 (file)
@@ -4575,7 +4575,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.  */
@@ -8292,10 +8293,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 (file)
index 0000000..4abe6ce
--- /dev/null
@@ -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();
+}