Another patch I'm working on revealed a couple of latent issues in specialization matching.

First, check_specialization_namespace takes the template as an argument, not the specialization; fixing this improves the error location on spec25.C.

Second, allowing determine_specialization to match a member of an uninstantiated class was leading to an abort in other code that relied on that not happening, since it's ill-formed.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 47e1174262229c446ff4cdb9a01e131ed269e7d3
Author: Jason Merrill <ja...@redhat.com>
Date:   Sun Aug 12 22:25:11 2012 -0400

    	* pt.c (register_specialization): Correct argument to
    	check_specialization_namespace.
    	(determine_specialization): Don't consider members of
    	unspecialized types.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ad81bab..580a3d4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -735,7 +735,7 @@ end_explicit_instantiation (void)
   processing_explicit_instantiation = false;
 }
 
-/* An explicit specialization or partial specialization TMPL is being
+/* An explicit specialization or partial specialization of TMPL is being
    declared.  Check that the namespace in which the specialization is
    occurring is permissible.  Returns false iff it is invalid to
    specialize TMPL in the current namespace.  */
@@ -1407,7 +1407,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
 		  DECL_SOURCE_LOCATION (clone)
 		    = DECL_SOURCE_LOCATION (fn);
 		}
-	      check_specialization_namespace (fn);
+	      check_specialization_namespace (tmpl);
 
 	      return fn;
 	    }
@@ -1804,6 +1804,16 @@ determine_specialization (tree template_id,
   if (template_id == error_mark_node || decl == error_mark_node)
     return error_mark_node;
 
+  /* We shouldn't be specializing a member template of an
+     unspecialized class template; we already gave an error in
+     check_specialization_scope, now avoid crashing.  */
+  if (template_count && DECL_CLASS_SCOPE_P (decl)
+      && template_class_depth (DECL_CONTEXT (decl)) > 0)
+    {
+      gcc_assert (errorcount);
+      return error_mark_node;
+    }
+
   fns = TREE_OPERAND (template_id, 0);
   explicit_targs = TREE_OPERAND (template_id, 1);
 
diff --git a/gcc/testsuite/g++.dg/template/spec25.C b/gcc/testsuite/g++.dg/template/spec25.C
index 3f641fe..385d19a 100644
--- a/gcc/testsuite/g++.dg/template/spec25.C
+++ b/gcc/testsuite/g++.dg/template/spec25.C
@@ -1,10 +1,10 @@
 namespace N {
   template <typename T>
   struct S {
-    void f() {}
+    void f() {}			// { dg-error "definition" }
   };
 }
 
 namespace K {
-  template <> void N::S<char>::f() {} // { dg-error "namespace|definition" }
+  template <> void N::S<char>::f() {} // { dg-error "different namespace" }
 }

Reply via email to