This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] PR c++/42225
- From: Dodji Seketeli <dodji at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: jason at redhat dot com
- Date: Thu, 3 Dec 2009 15:00:18 +0100
- Subject: [PATCH] PR c++/42225
Hello,
In this PR we omit to strip typedefs from TYPENAME_TYPEs. I noticed we also omit
it for DECLTYPE_TYPE expression that involve types, like in the typedef25.C
example in the patch below.
The change in convert_template_argument is just to factorize typedef stripping
from SCOPE_REFs.
Tested against trunk on x86_64-unknown-linux-gnu.
Dodji
commit eb317c85b6f8e2443b27977b24d0bad12e5aed7d
Author: Dodji Seketeli <dodji@redhat.com>
Date: Tue Dec 1 15:22:26 2009 +0100
Fix PR c++/42225
gcc/cp/ChangeLog:
PR c++/42225
* tree.c (strip_typedefs_from_expr): New function.
(strip_typedefs): Handle TYPENAME_TYPE and DECLTYPE_TYPE.
* pt.c (convert_template_argument): Use strip_typedefs_from_expr to
handle SCOPE_REFs.
gcc/testsuite/ChangeLog:
PR c++/42225
* g++.dg/template/typedef24.C: New test.
* g++.dg/template/typedef25.C: New test.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2d8f409..aac2f52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5170,6 +5170,7 @@ extern bool type_has_nontrivial_default_init (const_tree);
extern bool type_has_nontrivial_copy_init (const_tree);
extern bool class_tmpl_impl_spec_p (const_tree);
extern int zero_init_p (const_tree);
+extern tree strip_typedefs_from_expr (tree);
extern tree strip_typedefs (tree);
extern bool typedef_variant_p (tree);
extern tree copy_binfo (tree, tree, tree,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9fd06b3..1068001 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5527,12 +5527,8 @@ convert_template_argument (tree parm,
val = strip_typedefs (val);
}
else if (TREE_CODE (orig_arg) == SCOPE_REF)
- {
- /* Strip typedefs from the SCOPE_REF. */
- tree type = strip_typedefs (TREE_TYPE (orig_arg));
- tree scope = strip_typedefs (TREE_OPERAND (orig_arg, 0));
- val = build2 (SCOPE_REF, type, scope, TREE_OPERAND (orig_arg, 1));
- }
+ /* Strip typedefs from the SCOPE_REF. */
+ val = strip_typedefs_from_expr (orig_arg);
else
{
tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 17fc495..be6464c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -957,6 +957,48 @@ cv_unqualified (tree type)
return cp_build_qualified_type (type, quals);
}
+/* If EXPR is an expression or reference involving a type, strip typedefs
+ from its type part. E.g, if EXPR is a construct like: foo::bar, *foo::bar,
+ &foo::bar where foo is a type, strip typedefs from foo.
+ Otherwise, return EXPR unmodified.
+ This is a subroutine of strip_typedefs. */
+
+tree
+strip_typedefs_from_expr (tree expr)
+{
+ tree type, op0;
+ enum tree_code code;
+ char tclass;
+
+ if (expr)
+ code = TREE_CODE (expr);
+ else
+ return NULL_TREE;
+
+ tclass = TREE_CODE_CLASS (code);
+ if (tclass != tcc_expression && tclass != tcc_reference)
+ return expr;
+
+ switch (code)
+ {
+ case SCOPE_REF:
+ type = strip_typedefs (TREE_TYPE (expr));
+ op0 = strip_typedefs (TREE_OPERAND (expr, 0));
+ expr = build2 (code, type, op0, TREE_OPERAND (expr, 1));
+ break;
+ case INDIRECT_REF:
+ case ADDR_EXPR:
+ type = strip_typedefs (TREE_TYPE (expr));
+ op0 = strip_typedefs_from_expr (TREE_OPERAND (expr, 0));
+ expr = build1 (code, type, op0);
+ break;
+ default:
+ break;
+ }
+
+ return expr;
+}
+
/* Builds a qualified variant of T that is not a typedef variant.
E.g. consider the following declarations:
typedef const int ConstInt;
@@ -1009,6 +1051,19 @@ strip_typedefs (tree t)
result = build_ptrmemfunc_type (t0);
}
break;
+ case TYPENAME_TYPE:
+ t0 = strip_typedefs (TYPE_CONTEXT (t));
+ result = make_typename_type (t0, TYPENAME_TYPE_FULLNAME (t),
+ typename_type, tf_none);
+ break;
+ case DECLTYPE_TYPE:
+ t0 = strip_typedefs_from_expr (DECLTYPE_TYPE_EXPR (t));
+ result = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (result) = t0;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (result)
+ = DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t);
+ SET_TYPE_STRUCTURAL_EQUALITY (result);
+ break;
case ARRAY_TYPE:
type = strip_typedefs (TREE_TYPE (t));
t0 = strip_typedefs (TYPE_DOMAIN (t));;
diff --git a/gcc/testsuite/g++.dg/template/typedef24.C b/gcc/testsuite/g++.dg/template/typedef24.C
new file mode 100644
index 0000000..ad05846
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef24.C
@@ -0,0 +1,32 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/42225
+// { dg-do compile }
+
+template<class T>
+struct A
+{
+ typedef T I;
+};
+
+template<class T, int>
+struct B
+{
+ typedef T TT;
+ typedef typename TT::I TT_I;
+ typedef A<TT_I> TA;
+};
+
+template<class T>
+void
+foo()
+{
+ typedef T TT;
+ typedef typename TT::I TT_I;
+ typedef A<TT_I> TA;
+}
+
+int
+main()
+{
+ foo<A<int> >();
+}
diff --git a/gcc/testsuite/g++.dg/template/typedef25.C b/gcc/testsuite/g++.dg/template/typedef25.C
new file mode 100644
index 0000000..098a022
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef25.C
@@ -0,0 +1,42 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/42225
+// { dg-options "-std=c++0x" }
+// { dg-do compile }
+
+template<class T>
+struct A
+{
+ typedef T I;
+ static const char *i;
+};
+
+template<class T, int>
+struct B
+{
+ typedef T TT;
+ typedef decltype(TT::i) TT_I0;
+ typedef decltype(&TT::i) TT_I1;
+ typedef decltype(*TT::i) TT_I2;
+ typedef A<TT_I0> TA0;
+ typedef A<TT_I1> TA1;
+ typedef A<TT_I2> TA2;
+};
+
+template<class T>
+void
+foo()
+{
+ typedef T TT;
+ typedef decltype(TT::i) TT_I0;
+ typedef decltype(&TT::i) TT_I1;
+ typedef decltype(*TT::i) TT_I2;
+ typedef A<TT_I0> TA0;
+ typedef A<TT_I1> TA1;
+ typedef A<TT_I2> TA2;
+}
+
+int
+main()
+{
+ foo<A<int> >();
+}