The testcase in the BZ is invalid, but there's a valid variant that also ICEd. I've fixed the compiler to do the right thing with three different variants.

Tested x86_64-pc-linux-gnu, applying to trunk. Changes for the valid variant also applied to 5.
commit e99dbeae7942d066e234b3e31ec73e24d6aa2917
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Feb 24 13:26:12 2016 -0500

    	PR c++/69323 - valid
    
    	* pt.c (instantiate_class_template_1): Set
    	processing_template_decl before substituting friend_type.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 65edfa7..e9cdf6e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10180,11 +10180,11 @@ instantiate_class_template_1 (tree type)
 		       template <class U> friend class T::C;
 
 		     otherwise.  */
+		  /* Bump processing_template_decl in case this is something like
+		     template <class T> friend struct A<T>::B.  */
+		  ++processing_template_decl;
 		  friend_type = tsubst (friend_type, args,
 					tf_warning_or_error, NULL_TREE);
-		  /* Bump processing_template_decl for correct
-		     dependent_type_p calculation.  */
-		  ++processing_template_decl;
 		  if (dependent_type_p (friend_type))
 		    adjust_processing_template_decl = true;
 		  --processing_template_decl;
diff --git a/gcc/testsuite/g++.dg/template/friend61.C b/gcc/testsuite/g++.dg/template/friend61.C
new file mode 100644
index 0000000..1604f5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend61.C
@@ -0,0 +1,12 @@
+// PR c++/69323
+
+template<int VALUE>
+struct Outer
+{
+  struct StupidValueTrick
+  {
+    template<int VAL> friend struct Outer<VAL>::StupidValueTrick;
+  };
+};
+typedef Outer<42>::StupidValueTrick GoodValue;
+GoodValue good;

commit 63aabcee8f5bc478488102628e432dd3cbc0bbdc
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Feb 24 14:05:13 2016 -0500

    	PR c++/69323 - errors
    
    	* friend.c (make_friend_class): Likewise.
    	* decl.c (lookup_and_check_tag): Diagnose invalid dependent friend.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2df3398..5ec6589 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -12590,6 +12590,20 @@ lookup_and_check_tag (enum tag_types tag_code, tree name,
 					   decl,
 					   template_header_p
 					   | DECL_SELF_REFERENCE_P (decl));
+      if (template_header_p && t && CLASS_TYPE_P (t)
+	  && (!CLASSTYPE_TEMPLATE_INFO (t)
+	      || (!PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))))
+	{
+	  error ("%qT is not a template", t);
+	  inform (location_of (t), "previous declaration here");
+	  if (TYPE_CLASS_SCOPE_P (t)
+	      && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (t)))
+	    inform (input_location,
+		    "perhaps you want to explicitly add %<%T::%>",
+		    TYPE_CONTEXT (t));
+	  t = error_mark_node;
+	}
+
       return t;
     }
   else if (decl && TREE_CODE (decl) == TREE_LIST)
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 36b000f..5e4b2d1 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -255,6 +255,18 @@ make_friend_class (tree type, tree friend_type, bool complain)
 		 friend_type);
 	  return;
 	}
+      if (TYPE_TEMPLATE_INFO (friend_type)
+	  && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type)))
+	{
+	  error ("%qT is not a template", friend_type);
+	  inform (location_of (friend_type), "previous declaration here");
+	  if (TYPE_CLASS_SCOPE_P (friend_type)
+	      && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (friend_type))
+	      && currently_open_class (TYPE_CONTEXT (friend_type)))
+	    inform (input_location, "perhaps you need explicit template "
+		    "arguments in your nested-name-specifier");
+	  return;
+	}
     }
   else if (same_type_p (type, friend_type))
     {
diff --git a/gcc/testsuite/g++.dg/template/crash34.C b/gcc/testsuite/g++.dg/template/crash34.C
index ef4d21b..83dcc78 100644
--- a/gcc/testsuite/g++.dg/template/crash34.C
+++ b/gcc/testsuite/g++.dg/template/crash34.C
@@ -7,6 +7,6 @@
 
 class Foo;
 
-template <typename T> class Foo { }; // { dg-error "not a template type" }
+template <typename T> class Foo { }; // { dg-error "not a template" }
 
 Foo<int> x; // { dg-error "not a template|incomplete type" }
diff --git a/gcc/testsuite/g++.dg/template/friend61a.C b/gcc/testsuite/g++.dg/template/friend61a.C
new file mode 100644
index 0000000..d38e53a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend61a.C
@@ -0,0 +1,12 @@
+// PR c++/69323
+
+template<int VALUE>
+struct Outer
+{
+  struct StupidValueTrick
+  {
+    template<int VAL> friend struct StupidValueTrick; // { dg-error "not a template" }
+  };
+};
+typedef Outer<42>::StupidValueTrick GoodValue;
+GoodValue good;
diff --git a/gcc/testsuite/g++.dg/template/friend61b.C b/gcc/testsuite/g++.dg/template/friend61b.C
new file mode 100644
index 0000000..2da5d60
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend61b.C
@@ -0,0 +1,12 @@
+// PR c++/69323
+
+template<int VALUE>
+struct Outer
+{
+  struct StupidValueTrick
+  {
+    template<int VAL> friend struct Outer::StupidValueTrick; // { dg-error "not a template" }
+  };
+};
+typedef Outer<42>::StupidValueTrick GoodValue;
+GoodValue good;

Reply via email to