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" }
}