Commit cd41d410 by Dodji Seketeli Committed by Dodji Seketeli

Fix for PR c++/PR39754

gcc/cp/ChangeLog:
    PR c++/39754
    * cp-tree.h (canonical_type_variant): Remove this function declaration.
    (strip_typedefs): New function declaration.
    * tree.c (strip_typedefs): New function definition.
    (canonical_type_variant): Remove function definition.
    * cvt.c (convert_from_reference): No need to use
    canonical_type_variant.
    * typeck.c (cp_build_indirect_ref): Likewise.
    * error.c (dump_template_bindings): Use strip_typedefs instead of
    canonical_type_variant.
    * pt.c (convert_template_argument, unify): Likewise.
    * mangle.c (canonicalize_for_substitution): Don't use
    canonical_type_variant.

gcc/testsuite/ChangeLog:
    PR c++/39754
    * g++.dg/template/canon-type-1.C: New test.
    * g++.dg/template/canon-type-2.C: Likewise.
    * g++.dg/template/canon-type-3.C: Likewise.
    * g++.dg/template/canon-type-4.C: Likewise.
    * g++.dg/template/canon-type-5.C: Likewise.
    * g++.dg/template/canon-type-6.C: Likewise.
    * g++.dg/template/canon-type-7.C: Likewise.

From-SVN: r147951
parent 233215fe
2009-05-28 Dodji Seketeli <dodji@redhat.com>
PR c++/39754
* cp-tree.h (canonical_type_variant): Remove this function declaration.
(strip_typedefs): New function declaration.
* tree.c (strip_typedefs): New function definition.
(canonical_type_variant): Remove function definition.
* cvt.c (convert_from_reference): No need to use
canonical_type_variant.
* typeck.c (cp_build_indirect_ref): Likewise.
* error.c (dump_template_bindings): Use strip_typedefs instead of
canonical_type_variant.
* pt.c (convert_template_argument, unify): Likewise.
* mangle.c (canonicalize_for_substitution): Don't use
canonical_type_variant.
2009-05-27 Jason Merrill <jason@redhat.com> 2009-05-27 Jason Merrill <jason@redhat.com>
* call.c (implicit_conversion): Handle conversion from * call.c (implicit_conversion): Handle conversion from
......
...@@ -4827,7 +4827,7 @@ extern void init_tree (void); ...@@ -4827,7 +4827,7 @@ extern void init_tree (void);
extern int pod_type_p (const_tree); extern int pod_type_p (const_tree);
extern bool class_tmpl_impl_spec_p (const_tree); extern bool class_tmpl_impl_spec_p (const_tree);
extern int zero_init_p (const_tree); extern int zero_init_p (const_tree);
extern tree canonical_type_variant (tree); extern tree strip_typedefs (tree);
extern tree copy_binfo (tree, tree, tree, extern tree copy_binfo (tree, tree, tree,
tree *, int); tree *, int);
extern int member_p (const_tree); extern int member_p (const_tree);
......
...@@ -508,7 +508,7 @@ convert_from_reference (tree val) ...@@ -508,7 +508,7 @@ convert_from_reference (tree val)
{ {
if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE) if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
{ {
tree t = canonical_type_variant (TREE_TYPE (TREE_TYPE (val))); tree t = TREE_TYPE (TREE_TYPE (val));
tree ref = build1 (INDIRECT_REF, t, val); tree ref = build1 (INDIRECT_REF, t, val);
/* We *must* set TREE_READONLY when dereferencing a pointer to const, /* We *must* set TREE_READONLY when dereferencing a pointer to const,
......
...@@ -322,7 +322,7 @@ dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames) ...@@ -322,7 +322,7 @@ dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames)
t = tsubst (t, args, tf_none, NULL_TREE); t = tsubst (t, args, tf_none, NULL_TREE);
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because /* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
pp_simple_type_specifier doesn't know about it. */ pp_simple_type_specifier doesn't know about it. */
t = canonical_type_variant (t); t = strip_typedefs (t);
dump_type (t, TFF_PLAIN_IDENTIFIER); dump_type (t, TFF_PLAIN_IDENTIFIER);
} }
} }
......
...@@ -338,9 +338,14 @@ canonicalize_for_substitution (tree node) ...@@ -338,9 +338,14 @@ canonicalize_for_substitution (tree node)
/* For a TYPE_DECL, use the type instead. */ /* For a TYPE_DECL, use the type instead. */
if (TREE_CODE (node) == TYPE_DECL) if (TREE_CODE (node) == TYPE_DECL)
node = TREE_TYPE (node); node = TREE_TYPE (node);
if (TYPE_P (node)) if (TYPE_P (node)
node = canonical_type_variant (node); && TYPE_CANONICAL (node) != node
&& TYPE_MAIN_VARIANT (node) != node)
/* Here we want to strip the topmost typedef only.
We need to do that so is_std_substitution can do proper
name matching. */
node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
cp_type_quals (node));
return node; return node;
} }
......
...@@ -5073,7 +5073,7 @@ convert_template_argument (tree parm, ...@@ -5073,7 +5073,7 @@ convert_template_argument (tree parm,
the typedef, which is confusing if those future uses do not the typedef, which is confusing if those future uses do not
themselves also use the typedef. */ themselves also use the typedef. */
if (TYPE_P (val)) if (TYPE_P (val))
val = canonical_type_variant (val); val = strip_typedefs (val);
} }
else else
{ {
...@@ -13675,7 +13675,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) ...@@ -13675,7 +13675,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return 1; return 1;
/* Strip typedefs as in convert_template_argument. */ /* Strip typedefs as in convert_template_argument. */
arg = canonical_type_variant (arg); arg = strip_typedefs (arg);
} }
/* If ARG is a parameter pack or an expansion, we cannot unify /* If ARG is a parameter pack or an expansion, we cannot unify
......
...@@ -911,19 +911,111 @@ cp_build_qualified_type_real (tree type, ...@@ -911,19 +911,111 @@ cp_build_qualified_type_real (tree type,
return result; return result;
} }
/* Returns the canonical version of TYPE. In other words, if TYPE is /* Builds a qualified variant of T that is not a typedef variant.
a typedef, returns the underlying type. The cv-qualification of E.g. consider the following declarations:
the type returned matches the type input; they will always be typedef const int ConstInt;
compatible types. */ typedef ConstInt* PtrConstInt;
If T is PtrConstInt, this function returns a type representing
const int*.
In other words, if T is a typedef, the function returns the underlying type.
The cv-qualification and attributes of the type returned match the
input type.
They will always be compatible types.
The returned type is built so that all of its subtypes
recursively have their typedefs stripped as well.
This is different from just returning TYPE_CANONICAL (T)
Because of several reasons:
* If T is a type that needs structural equality
its TYPE_CANONICAL (T) will be NULL.
* TYPE_CANONICAL (T) desn't carry type attributes
and looses template parameter names. */
tree tree
canonical_type_variant (tree t) strip_typedefs (tree t)
{ {
if (t == error_mark_node) tree result = NULL, type = NULL, t0 = NULL;
return error_mark_node;
if (!t || t == error_mark_node || t == TYPE_CANONICAL (t))
return t;
gcc_assert (TYPE_P (t));
switch (TREE_CODE (t))
{
case POINTER_TYPE:
type = strip_typedefs (TREE_TYPE (t));
result = build_pointer_type (type);
break;
case REFERENCE_TYPE:
type = strip_typedefs (TREE_TYPE (t));
result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
break;
case OFFSET_TYPE:
t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t));
type = strip_typedefs (TREE_TYPE (t));
result = build_offset_type (t0, type);
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
{
t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t));
result = build_ptrmemfunc_type (t0);
}
break;
case ARRAY_TYPE:
type = strip_typedefs (TREE_TYPE (t));
t0 = strip_typedefs (TYPE_DOMAIN (t));;
result = build_cplus_array_type (type, t0);
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
{
tree arg_types = NULL, arg_node, arg_type;
for (arg_node = TYPE_ARG_TYPES (t);
arg_node;
arg_node = TREE_CHAIN (arg_node))
{
if (arg_node == void_list_node)
break;
arg_type = strip_typedefs (TREE_VALUE (arg_node));
gcc_assert (arg_type);
arg_types =
tree_cons (TREE_PURPOSE (arg_node), arg_type, arg_types);
}
if (arg_types)
arg_types = nreverse (arg_types);
/* A list of parameters not ending with an ellipsis
must end with void_list_node. */
if (arg_node)
arg_types = chainon (arg_types, void_list_node);
return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), cp_type_quals (t)); type = strip_typedefs (TREE_TYPE (t));
if (TREE_CODE (t) == METHOD_TYPE)
{
tree class_type = TREE_TYPE (TREE_VALUE (arg_types));
gcc_assert (class_type);
result =
build_method_type_directly (class_type, type,
TREE_CHAIN (arg_types));
}
else
result = build_function_type (type,
arg_types);
}
break;
default:
break;
}
if (!result)
result = TYPE_MAIN_VARIANT (t);
return cp_build_qualified_type (result, cp_type_quals (t));
} }
/* Makes a copy of BINFO and TYPE, which is to be inherited into a /* Makes a copy of BINFO and TYPE, which is to be inherited into a
graph dominated by T. If BINFO is NULL, TYPE is a dependent base, graph dominated by T. If BINFO is NULL, TYPE is a dependent base,
......
...@@ -2494,12 +2494,8 @@ cp_build_indirect_ref (tree ptr, const char *errorstring, ...@@ -2494,12 +2494,8 @@ cp_build_indirect_ref (tree ptr, const char *errorstring,
/* [expr.unary.op] /* [expr.unary.op]
If the type of the expression is "pointer to T," the type If the type of the expression is "pointer to T," the type
of the result is "T." of the result is "T." */
tree t = TREE_TYPE (type);
We must use the canonical variant because certain parts of
the back end, like fold, do pointer comparisons between
types. */
tree t = canonical_type_variant (TREE_TYPE (type));
if (CONVERT_EXPR_P (ptr) if (CONVERT_EXPR_P (ptr)
|| TREE_CODE (ptr) == VIEW_CONVERT_EXPR) || TREE_CODE (ptr) == VIEW_CONVERT_EXPR)
......
2009-05-28 Dodji Seketeli <dodji@redhat.com>
PR c++/39754
* g++.dg/template/canon-type-1.C: New test.
* g++.dg/template/canon-type-2.C: Likewise.
* g++.dg/template/canon-type-3.C: Likewise.
* g++.dg/template/canon-type-4.C: Likewise.
* g++.dg/template/canon-type-5.C: Likewise.
* g++.dg/template/canon-type-6.C: Likewise.
* g++.dg/template/canon-type-7.C: Likewise.
2009-05-28 Dave Korn <dave.korn.cygwin@gmail.com> 2009-05-28 Dave Korn <dave.korn.cygwin@gmail.com>
Uros Bizjak <ubizjak@gmail.com> Uros Bizjak <ubizjak@gmail.com>
Danny Smith <dansmister@gmail.com> Danny Smith <dansmister@gmail.com>
......
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
template < typename > struct A ;
template < typename T , typename = A < T > > struct B { } ;
template < class W , class > struct D
{
typedef W X ;
A<X*> a ;
};
template < class Y > struct E
{
B<Y*> b ;
} ;
E<int> e ;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
template < typename > struct A ;
template < typename T , typename = A < T > > struct B { } ;
template < class W , class > struct D
{
typedef W X ;
A< X()> a ;
};
template < class Y > struct E
{
B< Y()> b ;
};
E<int> e ;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
template<typename> struct A ;
template<typename T , typename = A<T> > struct B { } ;
template<class W , class > struct D
{
typedef W X ;
typedef X (FP) ();
A<FP&> a ;
} ;
template < class Y > struct E
{
typedef Y (FP) ();
B<FP&> b ;
} ;
E < int > e ;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
template<typename> struct A ;
template<typename T ,typename = A<T> > struct B { } ;
template<class W, class>
struct D
{
typedef W X;
A<X[2]> a;
} ;
template<class Y>
struct E
{
B<Y[2]> b;
};
E < int > e;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
struct Foo {};
template<typename> struct A ;
template<typename T ,typename = A<T> > struct B { } ;
template<class W, class>
struct D
{
typedef W X ;
A<X Foo::*> a ;
} ;
template<class Y>
struct E
{
B<Y Foo::*> b ;
} ;
E < int > e ;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
struct Foo {};
template<typename> struct A ;
template<typename T ,typename = A<T> > struct B { } ;
template<class W, class>
struct D
{
typedef W X;
A<void (Foo::*) (X)> a;
} ;
template<class Y>
struct E
{
B<void (Foo::*) (Y)> b;
};
E < int > e ;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/39754
// { dg-do "compile" }
struct Foo {};
template<typename> struct A ;
template<typename T ,typename = A<T> > struct B { } ;
template<class W, class>
struct D
{
typedef W X;
A<X (Foo::*) (X)> a ;
};
template<class Y>
struct E
{
B<Y (Foo::*) (Y)> b ;
};
E<int> e ;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment