C++ PATCH for c++/54744 (typename typedef used in mem-initializer)

Message ID 50C0FDDB.1080700@redhat.com
State New
Headers show

Commit Message

Jason Merrill Dec. 6, 2012, 8:19 p.m.
In the testcase, the derived class contains

   typedef typename derived::base_type::base_type base_type;

and then the constructor uses 'base_type' in a mem-initializer.  The 
lookup finds this typedef, and we then try to resolve it in order to 
determine whether it matches the current class.  When we try to resolve 
derived::base_type we find the typedef, and proceed into infinite recursion.

The pt.c hunk breaks this recursion by checking the recursion-break flag 
we already have in another place.  The other hunks avoid the need to 
resolve the typename at all for this testcase.

Tested x86_64-pc-linux-gnu, applying to trunk.  Applying just the pt.c 
hunk to 4.7.


commit 2459623f8dc5eb1a83ca589a4f6c4542825886f7
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Dec 6 10:59:46 2012 -0500

    	PR c++/54744
    	* pt.c (resolve_typename_type): Check TYPENAME_IS_RESOLVING_P on scope.
    	* init.c (expand_member_init): Check for being in a template first.
    	* parser.c (cp_parser_mem_initializer_list): Only check class types
    	for equivalence to the current class.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 76a31c1b..2206c16 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1370,8 +1370,8 @@  expand_member_init (tree name)
       tree virtual_binfo;
       int i;
-      if (same_type_p (basetype, current_class_type)
-	  || current_template_parms)
+      if (current_template_parms
+	  || same_type_p (basetype, current_class_type))
 	  return basetype;
       class_binfo = TYPE_BINFO (current_class_type);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a010f1f..3566d74 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11592,7 +11592,7 @@  cp_parser_mem_initializer_list (cp_parser* parser)
       /* Look for a target constructor. */
       if (mem_initializer != error_mark_node
-	  && TYPE_P (TREE_PURPOSE (mem_initializer))
+	  && CLASS_TYPE_P (TREE_PURPOSE (mem_initializer))
 	  && same_type_p (TREE_PURPOSE (mem_initializer), current_class_type))
 	  maybe_warn_cpp0x (CPP0X_DELEGATING_CTORS);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c1e12f0..2f27e10 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -20079,7 +20079,16 @@  resolve_typename_type (tree type, bool only_current_p)
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
   if (TREE_CODE (scope) == TYPENAME_TYPE)
-    scope = resolve_typename_type (scope, only_current_p);
+    {
+      if (TYPENAME_IS_RESOLVING_P (scope))
+	/* Given a class template A with a dependent base with nested type C,
+	   typedef typename A::C::C C will land us here, as trying to resolve
+	   the initial A::C leads to the local C typedef, which leads back to
+	   A::C::C.  So we break the recursion now.  */
+	return type;
+      else
+	scope = resolve_typename_type (scope, 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)
diff --git a/gcc/testsuite/g++.dg/template/meminit3.C b/gcc/testsuite/g++.dg/template/meminit3.C
new file mode 100644
index 0000000..b682449
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/meminit3.C
@@ -0,0 +1,12 @@ 
+// PR c++/54744
+template <typename T>
+struct base {
+  typedef base base_type;
+template <typename T>
+struct derived : base<T> {
+  typedef typename derived::base_type::base_type base_type;
+  derived() : base_type() {}