On Jan 24, 2019, Jason Merrill <ja...@redhat.com> wrote: > The latter; you can't have a partial specialization in a function.
*nod* (though not entirely reflected in the patch below, I see) >> Any suggestion of a good name for the inline function (or would you >> prefer it to be a macro?) that tests whether a decl satisfies this >> predicate? primary_or_partial_spec_p? > Sounds good. I was not entirely clear on what the predicate was supposed to be when I wrote the above. I hadn't fully realized we were testing properties of a template instantiation by inspecting mostly properties of the template, rather than of the instantiation proper. Once I realized that, I hesitated between introducing a function to test properties of the base template directly, or a function to test the instantiation for those properties. It wasn't clear to me that having e.g. only DECL_TI_TEMPLATE as an argument would be enough to test everything we needed: we wouldn't have the context (should be the same) or the template args (certainly not the same, but sharing the same depth?) of the instantiation we were supposed to assess to begin with. So I went with a different name that reflected more closely the test I implemented: instantiates_primary_template_p. Now, maybe we're better off with something that tests the template rather than the instantiation, to use at other places where PRIMARY_TEMPLATE_P is found insufficient. If that's the case, I'll have to figure out whether taking just the template is enough, or whether we need the tinfo object or are better off taking additional arguments. But since that will take additional investigation and you had nodded to the logic that involved the args of the instantiation, I'm leaving it at this for now. Please let me know whether the alternate form would be preferred. This patch bootstrapped on x86_64- and i686-linux-gnu, and is undergoing regression testing ATM. Ok to install if it passes? for gcc/cp/ChangeLog PR c++/87770 * pt.c (instantiates_primary_template_p): New. (type_dependent_expression_p): Use it. for gcc/testsuite/ChangeLog PR c++/87770 * g++.dg/pr87770.C: New. --- gcc/cp/pt.c | 55 +++++++++++++++++++++++++++++++++++++++- gcc/testsuite/g++.dg/pr87770.C | 11 ++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/pr87770.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 48c180cc13b3..d413fa81c59e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -400,6 +400,59 @@ template_class_depth (tree type) return depth; } +/* Return TRUE if NODE instantiates a template that has arguments of + its own, be it directly a primary template or indirectly through a + partial specializations. */ +static inline bool +instantiates_primary_template_p (tree node) +{ + tree tinfo; + if (!DECL_P (node)) + tinfo = CLASSTYPE_TEMPLATE_INFO (node); + else if (DECL_LANG_SPECIFIC (node)) + tinfo = DECL_TEMPLATE_INFO (node); + else + tinfo = NULL_TREE; + + if (!tinfo) + return false; + + tree tmpl = TI_TEMPLATE (tinfo); + if (PRIMARY_TEMPLATE_P (tmpl)) + return true; + + if (!DECL_TEMPLATE_SPECIALIZATION (tmpl)) + return false; + + /* So now we know we have a specialization, but it could be a full + or a partial specialization. To tell which, compare the depth of + its template arguments with those of its context. ??? How do we + tell apart a partial from a full explicit specialization in a + non-template context? */ + + tree ctxt; + if (!DECL_P (node)) + ctxt = TYPE_CONTEXT (node); + else + ctxt = DECL_CONTEXT (node); + + tree ctinfo; + if (!DECL_P (ctxt)) + ctinfo = CLASSTYPE_TEMPLATE_INFO (ctxt); + else if (DECL_LANG_SPECIFIC (ctxt)) + ctinfo = DECL_TEMPLATE_INFO (ctxt); + else + ctinfo = NULL_TREE; + + int cdepth; + if (!ctinfo) + cdepth = 0; + else + cdepth = TMPL_ARGS_DEPTH (TI_ARGS (ctinfo)); + + return (TMPL_ARGS_DEPTH (TI_ARGS (tinfo)) > cdepth); +} + /* Subroutine of maybe_begin_member_template_processing. Returns true if processing DECL needs us to push template parms. */ @@ -25622,7 +25675,7 @@ type_dependent_expression_p (tree expression) that come from the template-id; the template arguments for the enclosing class do not make it type-dependent unless they are used in the type of the decl. */ - if (PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (expression)) + if (instantiates_primary_template_p (expression) && (any_dependent_template_arguments_p (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression))))) return true; diff --git a/gcc/testsuite/g++.dg/pr87770.C b/gcc/testsuite/g++.dg/pr87770.C new file mode 100644 index 000000000000..69eff4a786fe --- /dev/null +++ b/gcc/testsuite/g++.dg/pr87770.C @@ -0,0 +1,11 @@ +// { dg-do compile } + +template <typename> struct d { + template <typename e> d(e); +}; +template <> template <typename e> d<int>::d(e); +template <> template <typename e> d<int>::d(e) { + long g; + (void)g; +} +template d<int>::d(char); -- Alexandre Oliva, freedom fighter https://FSFLA.org/blogs/lxo Be the change, be Free! FSF Latin America board member GNU Toolchain Engineer Free Software Evangelist Hay que enGNUrecerse, pero sin perder la terGNUra jamás-GNUChe