On Thu, Mar 1, 2018 at 9:41 AM, Jason Merrill <ja...@redhat.com> wrote:
> On Wed, Feb 28, 2018 at 4:04 PM, Paolo Carlini <paolo.carl...@oracle.com> 
> wrote:
>> On 28/02/2018 20:20, Jason Merrill wrote:
>>>
>>> Hmm, the test seems wrong; the diagnostic talks about specializing the
>>> arguments, but the actual test is checking whether the enclosing scope
>>> is fully specialized.  It looks like you'll give the same error for
>>>
>>> template <class T>
>>> struct A {
>>>    template <class U>
>>>    static const U u;
>>> };
>>>
>>> template <class T>
>>> template <class U>
>>> const U* A<T>::u<U*> = nullptr;
>>>
>>> which does specialize the argument; since we accept
>>>
>>> template <class T>
>>> struct A {
>>>    template <class U>
>>>    struct B;
>>> };
>>>
>>> template <class T>
>>> template <class U>
>>> struct A<T>::B<U*> { };
>>>
>>> we ought to accept the above as well.
>>>
>>> So, we could reject the testcase with this error, but we would need to
>>> test for it using the same check as in process_partial_specialization.
>>
>> I see. Doing that seems relatively easy - I have a draft which appears to
>> work - but then we have immediately to change the gcc_assert at the
>> beginning of determine_specialization to let such specializations through
>> (of course it still uses the wrong test!!).  I'm not sure about the best way
>> to do that... But that seems also doable.
>
> That test is correct for functions, I think we just want to restrict
> that block to functions.
>
>> The next problem is
>> duplicate_decls which apparently misses a bit of code to understand that the
>> new declaration does not conflict with the old one near line #1650... So,
>> frankly, I think that even with your great guidance I would need a few
>> iterations to get right the whole package and we are so damn close to the
>> release. What do you think? Do you want to take this over, or maybe you see
>> us restricting a bit what we'll have working in this area for 8.1.0?
>
> Yeah, I'll take it.

Ah, needed to fix the code in start_decl that checks for a variable
template specialization to consider that a specialization can be a
template.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 1c44723705fb34f8b3ccc0493a2a79230bb5a7d9
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Mar 1 10:16:13 2018 -0500

            PR c++/71569 - ICE with redundant args on member variable template.
    
            * decl.c (start_decl): Handle partial specialization of member
            variable template.
            * pt.c (determine_specialization): Allow partial specialization
            of member variable template without specializing enclosing class.
            (process_partial_specialization): Improve error message.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f1be2292c59..db64d12c95a 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5080,19 +5080,17 @@ 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)
+                  && (DECL_LANG_SPECIFIC (decl)
+                      && DECL_TEMPLATE_SPECIALIZATION (decl)))
+           /* OK, specialization was already checked.  */;
          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;
-               }
+             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
            {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 73451195cd0..e07d77bb87e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2060,7 +2060,8 @@ determine_specialization (tree template_id,
   /* 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)
+  if (!VAR_P (decl)
+      && template_count && DECL_CLASS_SCOPE_P (decl)
       && template_class_depth (DECL_CONTEXT (decl)) > 0)
     {
       gcc_assert (errorcount);
@@ -4840,10 +4841,13 @@ process_partial_specialization (tree decl)
     {
       if (!flag_concepts)
         error ("partial specialization %q+D does not specialize "
-              "any template arguments", decl);
+              "any template arguments; to define the primary template, "
+              "remove the template argument list", decl);
       else
         error ("partial specialization %q+D does not specialize any "
-              "template arguments and is not more constrained than", decl);
+              "template arguments and is not more constrained than "
+              "the primary template; to define the primary template, "
+              "remove the template argument list", decl);
       inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here");
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ58.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ58.C
new file mode 100644
index 00000000000..f9095f61e67
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ58.C
@@ -0,0 +1,12 @@
+// PR c++/71569
+// { dg-do compile { target c++14 } }
+
+template <class T>
+struct A {
+  template <class U>
+  static const U u;
+};
+
+template <class T>
+template <class U>
+const U A<T>::u<U> = 0;        // { dg-error "does not specialize" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ58a.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ58a.C
new file mode 100644
index 00000000000..850a2c9689c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ58a.C
@@ -0,0 +1,14 @@
+// PR c++/71569
+// { dg-do compile { target c++14 } }
+
+template <class T>
+struct A {
+  template <class U>
+  static const U u;
+};
+
+template <class T>
+template <class U>
+const U* A<T>::u<U*> = 0;
+
+const int *p = A<char>::u<int*>;

Reply via email to