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*>;