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>
* call.c (implicit_conversion): Handle conversion from
......
......@@ -4827,7 +4827,7 @@ extern void init_tree (void);
extern int pod_type_p (const_tree);
extern bool class_tmpl_impl_spec_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,
tree *, int);
extern int member_p (const_tree);
......
......@@ -508,7 +508,7 @@ convert_from_reference (tree val)
{
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);
/* 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)
t = tsubst (t, args, tf_none, NULL_TREE);
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
pp_simple_type_specifier doesn't know about it. */
t = canonical_type_variant (t);
t = strip_typedefs (t);
dump_type (t, TFF_PLAIN_IDENTIFIER);
}
}
......
......@@ -338,9 +338,14 @@ canonicalize_for_substitution (tree node)
/* For a TYPE_DECL, use the type instead. */
if (TREE_CODE (node) == TYPE_DECL)
node = TREE_TYPE (node);
if (TYPE_P (node))
node = canonical_type_variant (node);
if (TYPE_P (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;
}
......
......@@ -5073,7 +5073,7 @@ convert_template_argument (tree parm,
the typedef, which is confusing if those future uses do not
themselves also use the typedef. */
if (TYPE_P (val))
val = canonical_type_variant (val);
val = strip_typedefs (val);
}
else
{
......@@ -13675,7 +13675,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return 1;
/* 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
......
......@@ -911,19 +911,111 @@ cp_build_qualified_type_real (tree type,
return result;
}
/* Returns the canonical version of TYPE. In other words, if TYPE is
a typedef, returns the underlying type. The cv-qualification of
the type returned matches the type input; they will always be
compatible types. */
/* Builds a qualified variant of T that is not a typedef variant.
E.g. consider the following declarations:
typedef const int ConstInt;
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
canonical_type_variant (tree t)
strip_typedefs (tree t)
{
if (t == error_mark_node)
return error_mark_node;
tree result = NULL, type = NULL, t0 = NULL;
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
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,
/* [expr.unary.op]
If the type of the expression is "pointer to T," the type
of the result is "T."
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));
of the result is "T." */
tree t = TREE_TYPE (type);
if (CONVERT_EXPR_P (ptr)
|| 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>
Uros Bizjak <ubizjak@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