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

Reply via email to