This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/59956 (ICE with friend template)


In this testcase, tsubst_friend_function was getting confused trying to instantiate the friend template because it didn't recognize that it was a template. Fixed by keeping the TEMPLATE_DECL on the friends list and dealing with that appropriately in tsubst_friend_function. is_specialization_of_friend already handles it fine.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 0440d57fa786b012113a7dca2161557546b9b70b
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jan 29 15:14:23 2014 -0500

    	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.

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 7f1b6d5..548e191 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();
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]