diff mbox

C++ PATCH for c++/71738 (ICE with multi-template friend)

Message ID CADzB+2nk1gDHLapMz3wWKYRfN2ZfXntd80vyje7mAtZHxbrcZg@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill July 24, 2016, 2:39 a.m. UTC
Here lookup_template_class is tsubsting a TEMPLATE_DECL and then
crashing when it gets a TEMPLATE_DECL back, when a TEMPLATE_DECL is
what it wants to end up with anyway.  This is silly.

The testcase is also silly, since members have access to their
enclosing class and so the friend declaration has no effect.  Less
silly variants of the testcase still don't work.  But fixing this ICE
doesn't need to wait for the more general fix for multi-level template
friends.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 990c17ca879abf64c248d4f68fdb20937d515dbe
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jul 22 15:37:49 2016 -0400

    	PR c++/71738 - nested template friend
    
    	* pt.c (lookup_template_class_1): Handle getting template from tsubst.
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3ee53d1..a44bead 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8601,7 +8601,9 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	     for parameters in the TYPE_DECL of the alias template
 	     done earlier.  So be careful while getting the template
 	     of FOUND.  */
-	  found = TREE_CODE (found) == TYPE_DECL
+	  found = TREE_CODE (found) == TEMPLATE_DECL
+	    ? found
+	    : TREE_CODE (found) == TYPE_DECL
 	    ? TYPE_TI_TEMPLATE (TREE_TYPE (found))
 	    : CLASSTYPE_TI_TEMPLATE (found);
 	}
diff --git a/gcc/testsuite/g++.dg/template/friend63.C b/gcc/testsuite/g++.dg/template/friend63.C
new file mode 100644
index 0000000..f3a292c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend63.C
@@ -0,0 +1,29 @@ 
+// PR c++/71738
+
+template < class > struct S
+{
+  template < class > struct A
+  { 
+    template < class > struct B
+    {
+      template <class Z>
+      void operator=(Z) { S::i = 0; }
+    };
+  };
+
+  // Note that this friend declaration is useless, since nested classes are
+  // already friends of their enclosing class.
+  template < class X >
+  template < class Y >
+  template < class Z >
+  friend void A < X >::B < Y >::operator= (Z);
+
+private:
+  static int i;
+};
+
+int main()
+{
+  S<int>::A<int>::B<int> b;
+  b = 0;
+}