diff mbox

C++ PATCH for c++/71515 (typename in partial specialization)

Message ID CADzB+2kJz4OGCKfouxHwoZd6h30UFdt176Skr55c1Z6BeixVbQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill July 24, 2016, 11:39 p.m. UTC
Here we got into infinite recursion trying to determine if A<int> is
the same as A<T, typename A<T>::type> because we would keep trying to
resolve the typename, which would want to compare the types again to
see if A<T> is a currently open class, and so on.

This patch avoids this recursion by checking whether the typename
scope has TYPE_FIELDS set before we bother to see if it's a currently
open class; if TYPE_FIELDS isn't set then this particular dependent
template-id has not been defined as a partial specialization anywhere,
so there's no point in checking to see if it matches one of the
currently open classes.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 56912a98d98144373a621a87455dcb5721f346a8
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jul 22 14:42:53 2016 -0400

    	PR c++/71515 - typename in partial specialization
    
    	* pt.c (resolve_typename_type): Try to avoid calling
    	currently_open_class.
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 65fa982..a61f1c8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -23678,29 +23678,26 @@  resolve_typename_type (tree type, bool only_current_p)
     }
   /* If we don't know what SCOPE refers to, then we cannot resolve the
      TYPENAME_TYPE.  */
-  if (TREE_CODE (scope) == TYPENAME_TYPE)
-    return type;
-  /* If the SCOPE is a template type parameter, we have no way of
-     resolving the name.  */
-  if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM)
-    return type;
-  /* If the SCOPE is not the current instantiation, there's no reason
-     to look inside it.  */
-  if (only_current_p && !currently_open_class (scope))
+  if (!CLASS_TYPE_P (scope))
     return type;
   /* If this is a typedef, we don't want to look inside (c++/11987).  */
   if (typedef_variant_p (type))
     return type;
   /* If SCOPE isn't the template itself, it will not have a valid
      TYPE_FIELDS list.  */
-  if (CLASS_TYPE_P (scope)
-      && same_type_p (scope, CLASSTYPE_PRIMARY_TEMPLATE_TYPE (scope)))
+  if (same_type_p (scope, CLASSTYPE_PRIMARY_TEMPLATE_TYPE (scope)))
     /* scope is either the template itself or a compatible instantiation
        like X<T>, so look up the name in the original template.  */
     scope = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (scope);
-  else
-    /* scope is a partial instantiation, so we can't do the lookup or we
-       will lose the template arguments.  */
+  /* We shouldn't have built a TYPENAME_TYPE with a non-dependent scope.  */
+  gcc_checking_assert (uses_template_parms (scope));
+  /* If scope has no fields, it can't be a current instantiation.  Check this
+     before currently_open_class to avoid infinite recursion (71515).  */
+  if (!TYPE_FIELDS (scope))
+    return type;
+  /* If the SCOPE is not the current instantiation, there's no reason
+     to look inside it.  */
+  if (only_current_p && !currently_open_class (scope))
     return type;
   /* Enter the SCOPE so that name lookup will be resolved as if we
      were in the class definition.  In particular, SCOPE will no
diff --git a/gcc/testsuite/g++.dg/template/typename22.C b/gcc/testsuite/g++.dg/template/typename22.C
new file mode 100644
index 0000000..b5dc1b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typename22.C
@@ -0,0 +1,8 @@ 
+// PR c++/71515
+
+template < typename, typename = int > struct A;
+
+template < typename T > struct A < T, typename A < T >::type >
+{
+  A < int > *a;
+};