From 5b5d851ea0015765d83b329d93484dcd8ccc8c1e Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Fri, 22 Feb 2013 17:23:56 -0500
Subject: [PATCH] re PR c++/56395 (ICE, Segmentation fault in tsubst)

	PR c++/56395
	* tree.c (strip_typedefs): Strip typedefs from TYPENAME_TYPE template
	args.

From-SVN: r196228
---
 gcc/cp/ChangeLog                           |  6 +++++
 gcc/cp/tree.c                              | 31 +++++++++++++++++++---
 gcc/testsuite/g++.dg/template/typename19.C | 24 +++++++++++++++++
 3 files changed, 58 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/typename19.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b7816a903395..8f0872b13fcb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-22  Jason Merrill  <jason@redhat.com>
+
+	PR c++/56395
+	* tree.c (strip_typedefs): Strip typedefs from TYPENAME_TYPE template
+	args.
+
 2013-02-20  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/56373
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 41c8759096c3..75b4d5121ed4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1220,9 +1220,34 @@ strip_typedefs (tree t)
       }
       break;
     case TYPENAME_TYPE:
-      result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t)),
-				   TYPENAME_TYPE_FULLNAME (t),
-				   typename_type, tf_none);
+      {
+	tree fullname = TYPENAME_TYPE_FULLNAME (t);
+	if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR)
+	  {
+	    tree args = TREE_OPERAND (fullname, 1);
+	    tree new_args = copy_node (args);
+	    bool changed = false;
+	    for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
+	      {
+		tree arg = TREE_VEC_ELT (args, i);
+		tree strip_arg;
+		if (TYPE_P (arg))
+		  strip_arg = strip_typedefs (arg);
+		else
+		  strip_arg = strip_typedefs_expr (arg);
+		TREE_VEC_ELT (new_args, i) = strip_arg;
+		if (strip_arg != arg)
+		  changed = true;
+	      }
+	    if (changed)
+	      fullname = lookup_template_function (TREE_OPERAND (fullname, 0),
+						   new_args);
+	    else
+	      ggc_free (new_args);
+	  }
+	result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t)),
+				     fullname, typename_type, tf_none);
+      }
       break;
     case DECLTYPE_TYPE:
       result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t));
diff --git a/gcc/testsuite/g++.dg/template/typename19.C b/gcc/testsuite/g++.dg/template/typename19.C
new file mode 100644
index 000000000000..735deb277524
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typename19.C
@@ -0,0 +1,24 @@
+// PR c++/56395
+
+struct A
+{
+  template <class T> struct B { };
+};
+
+template <class T> struct D { };
+
+template <class T, class U> struct C
+{
+  typedef T _Type;
+  typedef typename T::template B<_Type> _BType;
+  D<_BType> d;
+};
+
+template <class T> struct C<T,T>
+{
+  typedef T _Type;
+  typedef typename T::template B<_Type> _BType;
+  D<_BType> d;
+};
+
+C<A,A> c;
-- 
GitLab