From 04ef83b79ab013b776448b1ffa8447fd6ecbd642 Mon Sep 17 00:00:00 2001
From: mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 8 Dec 2006 06:27:22 +0000
Subject: [PATCH] 	PR c++/29732 	* cp-tree.h (DECL_USE_TEMPLATE):
 Mention partial specializations. 	(explicit_class_specialization_p):
 Declare. 	* pt.c (explicit_class_specialization_p): New function. 
 * parser.c (cp_parser_init_declarator): Check correct number of 
 template parameters for in-class function definitions. 
 (cp_parser_check_declrator_template_parameters): Stop looking for 
 template classes when we find an explicit specialization. 	PR c++/29732 
 * g++.dg/template/crash65.C: New test. 	* g++.dg/template/spec16.C:
 Tweak error markers.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@119649 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/cp/ChangeLog                        | 11 +++++++++++
 gcc/cp/cp-tree.h                        | 11 +++++++++--
 gcc/cp/parser.c                         | 20 ++++++++++++--------
 gcc/cp/pt.c                             | 11 +++++++++++
 gcc/testsuite/ChangeLog                 |  6 ++++++
 gcc/testsuite/g++.dg/template/crash65.C |  7 +++++++
 gcc/testsuite/g++.dg/template/spec16.C  |  2 +-
 7 files changed, 57 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/crash65.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 213550807c0a..1a8d126bcf2e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2006-12-07  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/29732
+	* cp-tree.h (DECL_USE_TEMPLATE): Mention partial specializations.
+	(explicit_class_specialization_p): Declare.
+	* pt.c (explicit_class_specialization_p): New function.
+	* parser.c (cp_parser_init_declarator): Check correct number of
+	template parameters for in-class function definitions.
+	(cp_parser_check_declrator_template_parameters): Stop looking for
+	template classes when we find an explicit specialization.
+
 2006-12-07  Lee Millward  <lee.millward@codesourcery.com>
 
         PR c++/29980
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ae250bfbdfef..e59586bde77d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2879,8 +2879,14 @@ extern void decl_shadowed_for_var_insert (tree, tree);
    indicates the type of specializations:
 
      1=implicit instantiation
-     2=explicit specialization, e.g. int min<int> (int, int);
-     3=explicit instantiation, e.g. template int min<int> (int, int);
+
+     2=partial or explicit specialization, e.g.:
+
+        template <> int min<int> (int, int),
+
+     3=explicit instantiation, e.g.:
+  
+        template int min<int> (int, int);
 
    Note that NODE will be marked as a specialization even if the
    template it is instantiating is not a primary template.  For
@@ -4168,6 +4174,7 @@ extern tree build_non_dependent_expr		(tree);
 extern tree build_non_dependent_args		(tree);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree fold_non_dependent_expr		(tree);
+extern bool explicit_class_specialization_p     (tree);
 
 /* in repo.c */
 extern void init_repo				(void);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a0a6a1778550..d7611ed71ff1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11144,6 +11144,10 @@ cp_parser_init_declarator (cp_parser* parser,
   if (declarator == cp_error_declarator)
     return error_mark_node;
 
+  /* Check that the number of template-parameter-lists is OK.  */
+  if (!cp_parser_check_declarator_template_parameters (parser, declarator))
+    return error_mark_node;
+
   if (declares_class_or_enum & 2)
     cp_parser_check_for_definition_in_return_type (declarator,
 						   decl_specifiers->type);
@@ -11263,10 +11267,6 @@ cp_parser_init_declarator (cp_parser* parser,
   /* Check to see whether or not this declaration is a friend.  */
   friend_p = cp_parser_friend_p (decl_specifiers);
 
-  /* Check that the number of template-parameter-lists is OK.  */
-  if (!cp_parser_check_declarator_template_parameters (parser, declarator))
-    return error_mark_node;
-
   /* Enter the newly declared entry in the symbol table.  If we're
      processing a declaration in a class-specifier, we wait until
      after processing the initializer.  */
@@ -15312,10 +15312,14 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser,
 
 		 is correct; there shouldn't be a `template <>' for
 		 the definition of `S<int>::f'.  */
-	      if (CLASSTYPE_TEMPLATE_INFO (scope)
-		  && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope)
-		      || uses_template_parms (CLASSTYPE_TI_ARGS (scope)))
-		  && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
+	      if (!CLASSTYPE_TEMPLATE_INFO (scope))
+		/* If SCOPE does not have template information of any
+		   kind, then it is not a template, nor is it nested
+		   within a template.  */
+		break;
+	      if (explicit_class_specialization_p (scope))
+		break;
+	      if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
 		++num_templates;
 
 	      scope = TYPE_CONTEXT (scope);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index acaf6bce00f7..2cfcce501d9f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1316,6 +1316,17 @@ register_local_specialization (tree spec, tree tmpl)
   *slot = build_tree_list (spec, tmpl);
 }
 
+/* TYPE is a class type.  Returns true if TYPE is an explicitly
+   specialized class.  */
+
+bool
+explicit_class_specialization_p (tree type)
+{
+  if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+    return false;
+  return !uses_template_parms (CLASSTYPE_TI_ARGS (type));
+}
+
 /* Print the list of candidate FNS in an error message.  */
 
 void
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c5ab9b52fa7b..d1e707cc0942 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2006-12-07  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/29732
+	* g++.dg/template/crash65.C: New test.
+	* g++.dg/template/spec16.C: Tweak error markers.
+
 2006-12-07  Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
 	* gcc.target/spu: New directory.
diff --git a/gcc/testsuite/g++.dg/template/crash65.C b/gcc/testsuite/g++.dg/template/crash65.C
new file mode 100644
index 000000000000..4d49ecf3145a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/crash65.C
@@ -0,0 +1,7 @@
+// PR c++/29732
+
+struct A
+{
+  template<int> template<typename T> friend void foo(T) {} // { dg-error "parameter" }
+  void bar() { foo(0); } // { dg-error "foo" }
+};
diff --git a/gcc/testsuite/g++.dg/template/spec16.C b/gcc/testsuite/g++.dg/template/spec16.C
index c5bd5a95426e..881d7a091c29 100644
--- a/gcc/testsuite/g++.dg/template/spec16.C
+++ b/gcc/testsuite/g++.dg/template/spec16.C
@@ -7,5 +7,5 @@ struct A {
   template<int M> void B () ; 
 }; 
 
-void A<0>::B<0>() {    // { dg-error "explicit specialization" }
+void A<0>::B<0>() {    // { dg-error "parameter-lists" }
 } 
-- 
GitLab