diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b7816a90339..8f0872b13fc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2013-02-22 Jason Merrill + + PR c++/56395 + * tree.c (strip_typedefs): Strip typedefs from TYPENAME_TYPE template + args. + 2013-02-20 Paolo Carlini PR c++/56373 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 41c8759096c..75b4d5121ed 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 00000000000..735deb27752 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename19.C @@ -0,0 +1,24 @@ +// PR c++/56395 + +struct A +{ + template struct B { }; +}; + +template struct D { }; + +template struct C +{ + typedef T _Type; + typedef typename T::template B<_Type> _BType; + D<_BType> d; +}; + +template struct C +{ + typedef T _Type; + typedef typename T::template B<_Type> _BType; + D<_BType> d; +}; + +C c;