Basically all we need to do here is accept it, like check_classfn; all
the necessary checking was already done in check_explicit_specialization.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit f0ef26fb06fe5798cd7bb071a932a21cf5e5a878
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Sep 11 16:45:47 2014 -0400
PR c++/63201
* decl.c (start_decl): Handle specialization of member variable
template.
* pt.c (check_explicit_specialization): Adjust error.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6e195bb..59dada7 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4659,20 +4659,24 @@ start_decl (const cp_declarator *declarator,
if (field == NULL_TREE
|| !(VAR_P (field) || variable_template_p (field)))
error ("%q+#D is not a static data member of %q#T", decl, context);
+ else if (variable_template_p (field) && !this_tmpl)
+ {
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_SPECIALIZATION (decl))
+ /* OK, specialization was already checked. */;
+ else
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "non-member-template declaration of %qD", decl);
+ inform (DECL_SOURCE_LOCATION (field), "does not match "
+ "member template declaration here");
+ return error_mark_node;
+ }
+ }
else
{
if (variable_template_p (field))
- {
- if (!this_tmpl)
- {
- error_at (DECL_SOURCE_LOCATION (decl),
- "non-member-template declaration of %qD", decl);
- inform (DECL_SOURCE_LOCATION (field), "does not match "
- "member template declaration here");
- return error_mark_node;
- }
- field = DECL_TEMPLATE_RESULT (field);
- }
+ field = DECL_TEMPLATE_RESULT (field);
if (DECL_CONTEXT (field) != context)
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7f7ab93..008879b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2471,7 +2471,7 @@ check_explicit_specialization (tree declarator,
template <class T> void f<int>(); */
if (uses_template_parms (declarator))
- error ("function template partial specialization %qD "
+ error ("non-type partial specialization %qD "
"is not allowed", declarator);
else
error ("template-id %qD in declaration of primary template",
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ11.C b/gcc/testsuite/g++.dg/cpp1y/var-templ11.C
new file mode 100644
index 0000000..5d6e0d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ11.C
@@ -0,0 +1,67 @@
+// PR c++/63201
+// { dg-do compile { target c++14 } }
+
+template <class T>
+struct Y
+{
+ template <class U> static U x;
+};
+
+template <class T>
+template <class U>
+U Y<T>::x = U();
+
+template <>
+template <class U>
+U Y<int>::x = 42;
+
+template <>
+template <class U>
+// odd diagnostic
+U Y<float>::x<U> = 42; // { dg-error "partial specialization" }
+
+template <>
+template <>
+int Y<float>::x<int> = 42; // { dg-bogus "non-member-template declaration" }
+
+template <class T>
+struct Z
+{
+ template <class U> struct ZZ
+ {
+ template <class V> static V x;
+ };
+};
+
+template <class T>
+template <class U>
+template <class V>
+V Z<T>::ZZ<U>::x = V();
+
+template <>
+template <>
+template <class V>
+V Z<int>::ZZ<int>::x = V();
+
+template <>
+template <class U>
+struct Z<float>::ZZ
+{
+ template <class V> static V x;
+};
+
+template <>
+template <class U>
+template <class V>
+V Z<float>::ZZ<U>::x = V();
+
+template <>
+template <>
+template <>
+int Z<float>::ZZ<int>::x<int> = 42; // { dg-bogus "non-member-template declaration" }
+
+int main()
+{
+ int y = Y<int>::x<int>;
+ int z = Z<float>::ZZ<int>::x<int>;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C
index c272d94..ffc51ee 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb103.C
@@ -4,7 +4,7 @@
template <int nlimb, int i>
inline unsigned f (unsigned* ptr);
template <int nlimb>
-inline unsigned f<nlimb,nlimb> (unsigned* ptr) // { dg-error "function template partial specialization" }
+inline unsigned f<nlimb,nlimb> (unsigned* ptr) // { dg-error "partial specialization" }
{
return 1;
}