c-common.c (c_common_nodes_and_builtins): Since variants of void_type_node get built before it is given a name...

2007-01-02  Douglas Gregor  <doug.gregor@gmail.com>

	* c-common.c(c_common_nodes_and_builtins): Since variants of
	void_type_node get built before it is given a name, we need to
	give those variants the name, too. 
	(complete_array_type): We need to work with the canonical main
	type of the array, from which we will build the qualified version.
	* params.def (PARAM_VERIFY_CANONICAL_TYPES): New.
	* print-tree.c (print_node): Display canonical type information
	for each type.
	* stor-layout.c (layout_type): When we don't know the
	alignment of a type for which we're building an array, we end up
	guessing wrong, so make the type require structural equality.
	* tree.c (make_node_stat): When we build a new type, it is its
	own canonical type.
	(build_type_attribute_qual_variant): When building an attribute
	variant, its canonical type is the non-attribute variant. However,
	if the attributes are target-dependent and they differ, we need to
	use structural equality checks for this type.
	(build_qualified_type): A qualified type is not equivalent to its
	unqualified variant; set the canonical type appropriately.
	(build_distinct_type_copy): When building a distinct type from
	another type, the new type is its own canonical type.
	(build_variant_type_copy): When building a new type variant, we
	assume that it is equivalent to the original type.
	(build_pointer_type_for_mode): When building a pointer type, also
	build a canonical type pointer.
	(build_reference_type_for_mode): When building a reference type,
	also build a canonical type reference.
	(build_index_type): When we can't hash an index type (e.g.,
	because its maximum value is negative), the index type requires
	structural equality tests.
	(build_array_type): Build the canonical form of an array type.
	(build_function_type): Function types require structural equality,
	because they contain default arguments, attributes, etc. 
	(build_method_type_directly): Ditto for method types.
	(build_offset_type): Build the canonical offset type.
	(build_complex_type): Build the canonical vector type.
	(make_vector_type): Build the canonical vector type.
	* tree.h (TYPE_CANONICAL): New.
	(TYPE_STRUCTURAL_EQUALITY_P): New.
	(SET_TYPE_STRUCTURAL_EQUALITY): New.
	(struct tree_type): Added "canonical" field.
	* params.h (VERIFY_CANONICAL_TYPES): New.
	* doc/c-tree.texi (TYPE_CANONICAL): Document.
	(TYPE_STRUCTURAL_EQUALITY_P): Document.
	(SET_TYPE_STRUCTURAL_EQUALITY): Document.
	* doc/invoke.texi (verify-canonical-types): Document --param
	parameter for verifying canonical types.
	
2007-01-02  Douglas Gregor  <doug.gregor@gmail.com>

	* typeck.c (structural_comptypes): Renamed from "comptypes".
	(comptypes): Use canonical type information to perform fast type
	comparison. When VERIFY_CANONICAL_TYPES, verify that the
	canonical type comparison returns the same results as we would see
	from the current, structural check. Support COMPARE_STRUCTURAL
	when we need structural checks.
	* decl.c (typename_compare): Fix comment.
	(build_typename_type): TYPENAME_TYPE nodes require structural
	equality checks, because they resolve different based on the
	current class type.
	(make_unbound_class_template): UNBOUND_CLASS_TEMPLATE nodes
	require structural equality checks (for now).
	(build_ptrmemfunc_type): Build the canonical pointer to member
	function type.
	(compute_array_index_type): Whenever we build a new index type
	to represent the size of an array in a template, we need to mark
	this index type as requiring structural equality. This goes for
	arrays with value-dependent sizes with the current ABI, or all
	arrays with ABI-1.
	* tree.c (cplus_array_hash): New.
	(struct cplus_array_info): New.
	(cplus_array_compare): New.
	(cplus_array_htab): New.
	(build_cplus_array_type_1): Use a hash table to cache the array
	types we build. Build the canonical array type for each array
	type.
	(cp_build_qualified_type_real): When building a cv-qualified array
	type, use the hash table of array types and build canonical array
	types as necessary.
	(bind_template_template_parm): BOUND_TEMPLATE_TEMPLATE_PARM nodes
	use structural equality (for now).
	* cp-tree.h (COMPARE_STRUCTURAL): New.
	* pt.c (canonical_template_parms): New.
	(canonical_type_parameter): New.
	(process_template_parm): Find the canonical type parameter.
	(lookup_template_class): When we have named the primary template
	type, set the canonical type for our template class to the primary
	template type. If any of the template arguments need structural
	equality checks, the template class needs structural equality
	checks.
	(tsubst): When reducing the level of a template template
	parameter, we require structural equality tests for the resulting
	parameter because its template parameters have not had their types
	canonicalized. When reducing a template type parameter, find the
	canonical reduced type parameter.
	(any_template_arguments_need_structural_equality_p): New.

2007-01-02  Douglas Gregor  <doug.gregor@gmail.com>
	
	* objc-act.c (objc_build_volatilized_type): Keep track of
	canonical types.
	(objc_get_protocol_qualified_type): Ditto.

From-SVN: r120341
This commit is contained in:
Douglas Gregor 2007-01-02 14:23:26 +00:00 committed by Doug Gregor
parent eca0d5e8ce
commit 06d40de8bb
18 changed files with 701 additions and 23 deletions

View File

@ -1,3 +1,53 @@
2007-01-02 Douglas Gregor <doug.gregor@gmail.com>
* c-common.c(c_common_nodes_and_builtins): Since variants of
void_type_node get built before it is given a name, we need to
give those variants the name, too.
(complete_array_type): We need to work with the canonical main
type of the array, from which we will build the qualified version.
* params.def (PARAM_VERIFY_CANONICAL_TYPES): New.
* print-tree.c (print_node): Display canonical type information
for each type.
* stor-layout.c (layout_type): When we don't know the
alignment of a type for which we're building an array, we end up
guessing wrong, so make the type require structural equality.
* tree.c (make_node_stat): When we build a new type, it is its
own canonical type.
(build_type_attribute_qual_variant): When building an attribute
variant, its canonical type is the non-attribute variant. However,
if the attributes are target-dependent and they differ, we need to
use structural equality checks for this type.
(build_qualified_type): A qualified type is not equivalent to its
unqualified variant; set the canonical type appropriately.
(build_distinct_type_copy): When building a distinct type from
another type, the new type is its own canonical type.
(build_variant_type_copy): When building a new type variant, we
assume that it is equivalent to the original type.
(build_pointer_type_for_mode): When building a pointer type, also
build a canonical type pointer.
(build_reference_type_for_mode): When building a reference type,
also build a canonical type reference.
(build_index_type): When we can't hash an index type (e.g.,
because its maximum value is negative), the index type requires
structural equality tests.
(build_array_type): Build the canonical form of an array type.
(build_function_type): Function types require structural equality,
because they contain default arguments, attributes, etc.
(build_method_type_directly): Ditto for method types.
(build_offset_type): Build the canonical offset type.
(build_complex_type): Build the canonical vector type.
(make_vector_type): Build the canonical vector type.
* tree.h (TYPE_CANONICAL): New.
(TYPE_STRUCTURAL_EQUALITY_P): New.
(SET_TYPE_STRUCTURAL_EQUALITY): New.
(struct tree_type): Added "canonical" field.
* params.h (VERIFY_CANONICAL_TYPES): New.
* doc/c-tree.texi (TYPE_CANONICAL): Document.
(TYPE_STRUCTURAL_EQUALITY_P): Document.
(SET_TYPE_STRUCTURAL_EQUALITY): Document.
* doc/invoke.texi (verify-canonical-types): Document --param
parameter for verifying canonical types.
2007-01-02 Joseph Myers <joseph@codesourcery.com>
* config.gcc (powerpc-*-eabispe*, powerpc-*-eabisimaltivec*,

View File

@ -3458,6 +3458,16 @@ c_common_nodes_and_builtins (void)
record_builtin_type (RID_VOID, NULL, void_type_node);
/* Set the TYPE_NAME for any variants that were built before
record_builtin_type gave names to the built-in types. */
{
tree void_name = TYPE_NAME (void_type_node);
TYPE_NAME (void_type_node) = NULL_TREE;
TYPE_NAME (build_qualified_type (void_type_node, TYPE_QUAL_CONST))
= void_name;
TYPE_NAME (void_type_node) = void_name;
}
/* This node must not be shared. */
void_zero_node = make_node (INTEGER_CST);
TREE_TYPE (void_zero_node) = void_type_node;
@ -6294,6 +6304,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
{
tree maxindex, type, main_type, elt, unqual_elt;
int failure = 0, quals;
hashval_t hashcode = 0;
maxindex = size_zero_node;
if (initial_value)
@ -6370,6 +6381,12 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
TYPE_DOMAIN (main_type) = build_index_type (maxindex);
layout_type (main_type);
/* Make sure we have the canonical MAIN_TYPE. */
hashcode = iterative_hash_object (TYPE_HASH (unqual_elt), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (main_type)),
hashcode);
main_type = type_hash_canon (hashcode, main_type);
if (quals == 0)
type = main_type;
else

View File

@ -1,3 +1,52 @@
2007-01-02 Douglas Gregor <doug.gregor@gmail.com>
* typeck.c (structural_comptypes): Renamed from "comptypes".
(comptypes): Use canonical type information to perform fast type
comparison. When VERIFY_CANONICAL_TYPES, verify that the
canonical type comparison returns the same results as we would see
from the current, structural check. Support COMPARE_STRUCTURAL
when we need structural checks.
* decl.c (typename_compare): Fix comment.
(build_typename_type): TYPENAME_TYPE nodes require structural
equality checks, because they resolve different based on the
current class type.
(make_unbound_class_template): UNBOUND_CLASS_TEMPLATE nodes
require structural equality checks (for now).
(build_ptrmemfunc_type): Build the canonical pointer to member
function type.
(compute_array_index_type): Whenever we build a new index type
to represent the size of an array in a template, we need to mark
this index type as requiring structural equality. This goes for
arrays with value-dependent sizes with the current ABI, or all
arrays with ABI-1.
* tree.c (cplus_array_hash): New.
(struct cplus_array_info): New.
(cplus_array_compare): New.
(cplus_array_htab): New.
(build_cplus_array_type_1): Use a hash table to cache the array
types we build. Build the canonical array type for each array
type.
(cp_build_qualified_type_real): When building a cv-qualified array
type, use the hash table of array types and build canonical array
types as necessary.
(bind_template_template_parm): BOUND_TEMPLATE_TEMPLATE_PARM nodes
use structural equality (for now).
* cp-tree.h (COMPARE_STRUCTURAL): New.
* pt.c (canonical_template_parms): New.
(canonical_type_parameter): New.
(process_template_parm): Find the canonical type parameter.
(lookup_template_class): When we have named the primary template
type, set the canonical type for our template class to the primary
template type. If any of the template arguments need structural
equality checks, the template class needs structural equality
checks.
(tsubst): When reducing the level of a template template
parameter, we require structural equality tests for the resulting
parameter because its template parameters have not had their types
canonicalized. When reducing a template type parameter, find the
canonical reduced type parameter.
(any_template_arguments_need_structural_equality_p): New.
2006-12-31 Simon Martin <simartin@users.sourceforge.net>
PR c++/29731

View File

@ -3508,6 +3508,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
#define COMPARE_REDECLARATION 4 /* The comparison is being done when
another declaration of an existing
entity is seen. */
#define COMPARE_STRUCTURAL 8 /* The comparison is intended to be
structural. The actual comparison
will be identical to
COMPARE_STRICT. */
/* Used with push_overloaded_decl. */
#define PUSH_GLOBAL 0 /* Push the DECL into namespace scope,

View File

@ -2695,7 +2695,8 @@ typedef struct typename_info {
bool class_p;
} typename_info;
/* Compare two TYPENAME_TYPEs. K1 and K2 are really of type `tree'. */
/* Compare two TYPENAME_TYPEs. K1 is really of type `tree', K2 is
really of type `typename_info*' */
static int
typename_compare (const void * k1, const void * k2)
@ -2766,6 +2767,11 @@ build_typename_type (tree context, tree name, tree fullname,
/* Store it in the hash table. */
*e = t;
/* TYPENAME_TYPEs must always be compared structurally, because
they may or may not resolve down to another type depending on
the currently open classes. */
SET_TYPE_STRUCTURAL_EQUALITY (t);
}
return t;
@ -2937,6 +2943,7 @@ make_unbound_class_template (tree context, tree name, tree parm_list,
t = make_aggr_type (UNBOUND_CLASS_TEMPLATE);
TYPE_CONTEXT (t) = FROB_CONTEXT (context);
TREE_TYPE (t) = NULL_TREE;
SET_TYPE_STRUCTURAL_EQUALITY (t);
/* Build the corresponding TEMPLATE_DECL. */
d = build_decl (TEMPLATE_DECL, name, t);
@ -6461,6 +6468,11 @@ build_ptrmemfunc_type (tree type)
later. */
TYPE_SET_PTRMEMFUNC_TYPE (type, t);
if (TYPE_STRUCTURAL_EQUALITY_P (type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (type) != type)
TYPE_CANONICAL (t) = build_ptrmemfunc_type (TYPE_CANONICAL (type));
return t;
}
@ -6535,6 +6547,7 @@ compute_array_index_type (tree name, tree size)
{
tree type;
tree itype;
tree abi_1_itype = NULL_TREE;
if (error_operand_p (size))
return error_mark_node;
@ -6551,14 +6564,26 @@ compute_array_index_type (tree name, tree size)
type = TREE_TYPE (size);
}
if (abi_version_at_least (2)
/* We should only handle value dependent expressions specially. */
? value_dependent_expression_p (size)
/* But for abi-1, we handled all instances in templates. This
effects the manglings produced. */
: processing_template_decl)
return build_index_type (build_min (MINUS_EXPR, sizetype,
size, integer_one_node));
if (value_dependent_expression_p (size))
{
/* We cannot do any checking for a value-dependent SIZE. Just
build the index type and mark that it requires structural
equality checks. */
itype = build_index_type (build_min (MINUS_EXPR, sizetype,
size, integer_one_node));
SET_TYPE_STRUCTURAL_EQUALITY (itype);
return itype;
}
if (!abi_version_at_least (2) && processing_template_decl)
/* For abi-1, we handled all instances in templates the same way,
even when they were non-dependent. This effects the manglings
produced. So, we do the normal checking for non-dependent
sizes, but at the end we'll return the same type that abi-1
would have, but with TYPE_CANONICAL set to the "right"
value that the current ABI would provide. */
abi_1_itype = build_index_type (build_min (MINUS_EXPR, sizetype,
size, integer_one_node));
/* The size might be the result of a cast. */
STRIP_TYPE_NOPS (size);
@ -6649,7 +6674,14 @@ compute_array_index_type (tree name, tree size)
}
/* Create and return the appropriate index type. */
return build_index_type (itype);
if (abi_1_itype)
{
tree t = build_index_type (itype);
TYPE_CANONICAL (abi_1_itype) = TYPE_CANONICAL (t);
return abi_1_itype;
}
else
return build_index_type (itype);
}
/* Returns the scope (if any) in which the entity declared by

View File

@ -80,6 +80,12 @@ static tree cur_stmt_expr;
local variables. */
static htab_t local_specializations;
/* Contains canonical template parameter types. The vector is index by
the TEMPLATE_TYPE_IDX of the template parameter. Each element is a
TREE_LIST, whose TREE_VALUEs contain the canonical template
parameters of various types and levels. */
static GTY(()) VEC(tree,gc) *canonical_template_parms;
#define UNIFY_ALLOW_NONE 0
#define UNIFY_ALLOW_MORE_CV_QUAL 1
#define UNIFY_ALLOW_LESS_CV_QUAL 2
@ -157,6 +163,7 @@ static tree copy_default_args_to_explicit_spec_1 (tree, tree);
static void copy_default_args_to_explicit_spec (tree);
static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
static int eq_local_specializations (const void *, const void *);
static bool any_template_arguments_need_structural_equality_p (tree);
static bool dependent_type_p_r (tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree);
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool);
@ -2335,6 +2342,35 @@ build_template_parm_index (int index,
return t;
}
/* Find the canonical type parameter for the given template type
parmaeter. Returns the canonical type parameter, which may be TYPE
if no such parameter existed. */
static tree
canonical_type_parameter (tree type)
{
tree list;
int idx = TEMPLATE_TYPE_IDX (type);
if (!canonical_template_parms)
canonical_template_parms = VEC_alloc (tree, gc, idx+1);
while (VEC_length (tree, canonical_template_parms) <= (unsigned)idx)
VEC_safe_push (tree, gc, canonical_template_parms, NULL_TREE);
list = VEC_index (tree, canonical_template_parms, idx);
while (list && !comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL))
list = TREE_CHAIN (list);
if (list)
return TREE_VALUE (list);
else
{
VEC_replace(tree, canonical_template_parms, idx,
tree_cons (NULL_TREE, type,
VEC_index (tree, canonical_template_parms, idx)));
return type;
}
}
/* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
TEMPLATE_PARM_LEVEL has been decreased by LEVELS. If such a
TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
@ -2473,6 +2509,7 @@ process_template_parm (tree list, tree parm, bool is_non_type)
= build_template_parm_index (idx, processing_template_decl,
processing_template_decl,
decl, TREE_TYPE (parm));
TYPE_CANONICAL (t) = canonical_type_parameter (t);
}
DECL_ARTIFICIAL (decl) = 1;
SET_DECL_TEMPLATE_PARM_P (decl);
@ -4807,6 +4844,17 @@ lookup_template_class (tree d1,
/* A local class. Make sure the decl gets registered properly. */
if (context == current_function_decl)
pushtag (DECL_NAME (template), t, /*tag_scope=*/ts_current);
if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), arglist))
/* This instantiation is another name for the primary
template type. Set the TYPE_CANONICAL field
appropriately. */
TYPE_CANONICAL (t) = template_type;
else if (any_template_arguments_need_structural_equality_p (arglist))
/* Some of the template arguments require structural
equality testing, so this template class requires
structural equality testing. */
SET_TYPE_STRUCTURAL_EQUALITY (t);
}
/* If we called start_enum or pushtag above, this information
@ -7473,6 +7521,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
TYPE_POINTER_TO (r) = NULL_TREE;
TYPE_REFERENCE_TO (r) = NULL_TREE;
if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM)
/* We have reduced the level of the template
template parameter, but not the levels of its
template parameters, so canonical_type_parameter
will not be able to find the canonical template
template parameter for this level. Thus, we
require structural equality checking to compare
TEMPLATE_TEMPLATE_PARMs. */
SET_TYPE_STRUCTURAL_EQUALITY (r);
else
TYPE_CANONICAL (r) = canonical_type_parameter (r);
if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
tree argvec = tsubst (TYPE_TI_ARGS (t), args,
@ -13167,6 +13227,40 @@ dependent_template_arg_p (tree arg)
|| value_dependent_expression_p (arg));
}
/* Returns true if ARGS (a collection of template arguments) contains
any types that require structural equality testing. */
bool
any_template_arguments_need_structural_equality_p (tree args)
{
int i;
int j;
if (!args)
return false;
if (args == error_mark_node)
return true;
for (i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
{
tree level = TMPL_ARGS_LEVEL (args, i + 1);
for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
{
tree arg = TREE_VEC_ELT (level, j);
if (TREE_CODE (arg) == TEMPLATE_DECL
|| TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
continue;
else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
return true;
else if (!TYPE_P (arg) && TREE_TYPE (arg)
&& TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
return true;
}
}
return false;
}
/* Returns true if ARGS (a collection of template arguments) contains
any dependent arguments. */

View File

@ -407,6 +407,49 @@ rvalue (tree expr)
}
/* Hash an ARRAY_TYPE. K is really of type `tree'. */
static hashval_t
cplus_array_hash (const void* k)
{
hashval_t hash;
tree t = (tree) k;
hash = (htab_hash_pointer (TREE_TYPE (t))
^ htab_hash_pointer (TYPE_DOMAIN (t)));
return hash;
}
typedef struct cplus_array_info {
tree type;
tree domain;
} cplus_array_info;
/* Compare two ARRAY_TYPEs. K1 is really of type `tree', K2 is really
of type `cplus_array_info*'. */
static int
cplus_array_compare (const void * k1, const void * k2)
{
tree t1 = (tree) k1;
const cplus_array_info *t2 = (const cplus_array_info*) k2;
if (!comptypes (TREE_TYPE (t1), t2->type, COMPARE_STRUCTURAL))
return 0;
if (!TYPE_DOMAIN (t1))
return !t2->domain;
if (!t2->domain)
return 0;
return comptypes (TYPE_DOMAIN (t1), t2->domain, COMPARE_STRUCTURAL);
}
static GTY ((param_is (union tree_node))) htab_t cplus_array_htab;
static tree
build_cplus_array_type_1 (tree elt_type, tree index_type)
{
@ -419,9 +462,47 @@ build_cplus_array_type_1 (tree elt_type, tree index_type)
|| (index_type
&& value_dependent_expression_p (TYPE_MAX_VALUE (index_type))))
{
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
void **e;
cplus_array_info cai;
hashval_t hash;
if (cplus_array_htab == NULL)
cplus_array_htab = htab_create_ggc (61, &cplus_array_hash,
&cplus_array_compare, NULL);
hash = (htab_hash_pointer (elt_type)
^ htab_hash_pointer (index_type));
cai.type = elt_type;
cai.domain = index_type;
e = htab_find_slot_with_hash (cplus_array_htab, &cai, hash, INSERT);
if (*e)
/* We have found the type: we're done. */
return (tree) *e;
else
{
/* Build a new array type. */
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
/* Complete building the array type. */
if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
|| (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type)))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (elt_type) != elt_type
|| (index_type
&& TYPE_CANONICAL (index_type) != index_type))
TYPE_CANONICAL (t)
= TYPE_CANONICAL
(build_cplus_array_type_1 (TYPE_CANONICAL (elt_type),
index_type?
TYPE_CANONICAL (index_type)
: index_type));
/* Store it in the hash table. */
*e = t;
}
}
else
t = build_array_type (elt_type, index_type);
@ -508,10 +589,59 @@ cp_build_qualified_type_real (tree type,
if (!t)
{
tree domain = TYPE_DOMAIN (type);
/* Make a new array type, just like the old one, but with the
appropriately qualified element type. */
t = build_variant_type_copy (type);
TREE_TYPE (t) = element_type;
/* This is a new type. */
TYPE_CANONICAL (t) = t;
if (dependent_type_p (element_type)
|| (domain
&& value_dependent_expression_p (TYPE_MAX_VALUE (domain))))
{
/* The new dependent array type we just created might be
equivalent to an existing dependent array type, so we
need to keep track of this new array type with a
lookup into CPLUS_ARRAY_HTAB. Note that we cannot
directly call build_cplus_array_type (that would
recurse) or build_cplus_array_type_1 (that would lose
attributes). */
void **e;
cplus_array_info cai;
hashval_t hash;
if (cplus_array_htab == NULL)
cplus_array_htab = htab_create_ggc (61, &cplus_array_hash,
&cplus_array_compare,
NULL);
hash = (htab_hash_pointer (element_type)
^ htab_hash_pointer (domain));
cai.type = element_type;
cai.domain = domain;
e = htab_find_slot_with_hash (cplus_array_htab, &cai, hash,
INSERT);
if (! *e)
/* Save this new type. */
*e = t;
}
if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (t))
|| (TYPE_DOMAIN (t)
&& TYPE_STRUCTURAL_EQUALITY_P (TYPE_DOMAIN (t))))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else
TYPE_CANONICAL (t)
= TYPE_CANONICAL
(build_array_type (TYPE_CANONICAL (TREE_TYPE (t)),
TYPE_DOMAIN (t)?
TYPE_CANONICAL (TYPE_DOMAIN(t))
: TYPE_DOMAIN (t)));
}
/* Even if we already had this variant, we update
@ -1003,6 +1133,7 @@ bind_template_template_parm (tree t, tree newargs)
TYPE_NAME (t2) = decl;
TYPE_STUB_DECL (t2) = decl;
TYPE_SIZE (t2) = 0;
SET_TYPE_STRUCTURAL_EQUALITY (t2);
return t2;
}

View File

@ -43,6 +43,7 @@ Boston, MA 02110-1301, USA. */
#include "target.h"
#include "convert.h"
#include "c-common.h"
#include "params.h"
static tree pfn_from_ptrmemfunc (tree);
static tree convert_for_assignment (tree, tree, const char *, tree, int);
@ -927,11 +928,10 @@ comp_array_types (tree t1, tree t2, bool allow_redeclaration)
return true;
}
/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
is a bitwise-or of the COMPARE_* flags. */
/* Subroutine in comptypes. */
bool
comptypes (tree t1, tree t2, int strict)
static bool
structural_comptypes (tree t1, tree t2, int strict)
{
if (t1 == t2)
return true;
@ -1090,6 +1090,65 @@ comptypes (tree t1, tree t2, int strict)
return targetm.comp_type_attributes (t1, t2);
}
/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
is a bitwise-or of the COMPARE_* flags. */
bool
comptypes (tree t1, tree t2, int strict)
{
if (strict == COMPARE_STRICT)
{
bool result;
if (t1 == t2)
return true;
if (t1 == error_mark_node || t2 == error_mark_node)
return false;
if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2))
/* At least one of the types requires structural equality, so
perform a deep check. */
return structural_comptypes (t1, t2, strict);
if (VERIFY_CANONICAL_TYPES)
{
result = structural_comptypes (t1, t2, strict);
if (result && TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
{
/* The two types are structurally equivalent, but their
canonical types were different. This is a failure of the
canonical type propagation code.*/
warning(0,
"canonical types differ for identical types %T and %T",
t1, t2);
debug_tree (t1);
debug_tree (t2);
}
else if (!result && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
{
/* Two types are structurally different, but the canonical
types are the same. This means we were over-eager in
assigning canonical types. */
warning (0,
"same canonical type node for different types %T and %T",
t1, t2);
debug_tree (t1);
debug_tree (t2);
}
return result;
}
else
return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
}
else if (strict == COMPARE_STRUCTURAL)
return structural_comptypes (t1, t2, COMPARE_STRICT);
else
return structural_comptypes (t1, t2, strict);
}
/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */
bool

View File

@ -305,6 +305,9 @@ The elements are indexed from zero.
@findex TYPENAME_TYPE_FULLNAME
@findex TYPE_FIELDS
@findex TYPE_PTROBV_P
@findex TYPE_CANONICAL
@findex TYPE_STRUCTURAL_EQUALITY_P
@findex SET_TYPE_STRUCTURAL_EQUALITY
All types have corresponding tree nodes. However, you should not assume
that there is exactly one tree node corresponding to each type. There
@ -406,6 +409,52 @@ does not hold for the generic pointer to object type @code{void *}. You
may use @code{TYPE_PTROBV_P} to test for a pointer to object type as
well as @code{void *}.
@item TYPE_CANONICAL
This macro returns the ``canonical'' type for the given type
node. Canonical types are used to improve performance in the C++ and
Objective-C++ front ends by allowing efficient comparison between two
type nodes in @code{same_type_p}: if the @code{TYPE_CANONICAL} values
of the types are equal, the types are equivalent; otherwise, the types
are not equivalent. The notion of equivalence for canonical types is
the same as the notion of type equivalence in the language itself. For
instance,
When @code{TYPE_CANONICAL} is @code{NULL_TREE}, there is no canonical
type for the given type node. In this case, comparison between this
type and any other type requires the compiler to perform a deep,
``structural'' comparison to see if the two type nodes have the same
form and properties.
The canonical type for a node is always the most fundamental type in
the equivalence class of types. For instance, @code{int} is its own
canonical type. A typedef @code{I} of @code{int} will have @code{int}
as its canonical type. Similarly, @code{I*}@ and a typedef @code{IP}@
(defined to @code{I*}) will has @code{int*} as their canonical
type. When building a new type node, be sure to set
@code{TYPE_CANONICAL} to the appropriate canonical type. If the new
type is a compound type (built from other types), and any of those
other types require structural equality, use
@code{SET_TYPE_STRUCTURAL_EQUALITY} to ensure that the new type also
requires structural equality. Finally, if for some reason you cannot
guarantee that @code{TYPE_CANONICAL} will point to the canonical type,
use @code{SET_TYPE_STRUCTURAL_EQUALITY} to make sure that the new
type--and any type constructed based on it--requires structural
equality. If you suspect that the canonical type system is
miscomparing types, pass @code{--param verify-canonical-types=1} to
the compiler or configure with @code{--enable-checking} to force the
compiler to verify its canonical-type comparisons against the
structural comparisons; the compiler will then print any warnings if
the canonical types miscompare.
@item TYPE_STRUCTURAL_EQUALITY_P
This predicate holds when the node requires structural equality
checks, e.g., when @code{TYPE_CANONICAL} is @code{NULL_TREE}.
@item SET_TYPE_STRUCTURAL_EQUALITY
This macro states that the type node it is given requires structural
equality checks, e.g., it sets @code{TYPE_CANONICAL} to
@code{NULL_TREE}.
@item same_type_p
This predicate takes two types as input, and holds if they are the same
type. For example, if one type is a @code{typedef} for the other, or

View File

@ -6383,6 +6383,13 @@ The size of cache line in L1 cache, in bytes.
@item l1-cache-size
The number of cache lines in L1 cache.
@item verify-canonical-types
Whether the compiler should verify the ``canonical'' types used for
type equality comparisons within the C++ and Objective-C++ front
ends. Set to 1 (the default when GCC is configured with
--enable-checking) to enable verification, 0 to disable verification
(the default when GCC is configured with --disable-checking).
@end table
@end table

View File

@ -1,3 +1,9 @@
2007-01-02 Douglas Gregor <doug.gregor@gmail.com>
* objc-act.c (objc_build_volatilized_type): Keep track of
canonical types.
(objc_get_protocol_qualified_type): Ditto.
2006-11-02 Andreas Tobler <a.tobler@schweiz.org>
* objc-act.c (objc_finish_file): Remove ifdef clause for OBJCPLUS and

View File

@ -908,6 +908,14 @@ objc_build_volatilized_type (tree type)
t = build_variant_type_copy (type);
TYPE_VOLATILE (t) = 1;
/* Set up the canonical type information. */
if (TYPE_STRUCTURAL_EQUALITY_P (type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (type) != type)
TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
else
TYPE_CANONICAL (t) = t;
return t;
}
@ -1370,7 +1378,13 @@ objc_get_protocol_qualified_type (tree interface, tree protocols)
to the pointee. */
if (is_ptr)
{
TREE_TYPE (type) = build_variant_type_copy (TREE_TYPE (type));
tree orig_pointee_type = TREE_TYPE (type);
TREE_TYPE (type) = build_variant_type_copy (orig_pointee_type);
/* Set up the canonical type information. */
TYPE_CANONICAL (type)
= TYPE_CANONICAL (TYPE_POINTER_TO (orig_pointee_type));
TYPE_POINTER_TO (TREE_TYPE (type)) = type;
type = TREE_TYPE (type);
}

View File

@ -626,6 +626,19 @@ DEFPARAM (PARAM_L1_CACHE_LINE_SIZE,
"The size of L1 cache line",
32, 0, 0)
#ifdef ENABLE_CHECKING
# define GCC_CANONICAL_TYPES_DEFAULT 1
#else
# define GCC_CANONICAL_TYPES_DEFAULT 0
#endif
/* Whether we should verify that the canonical types in the system are
consistent with the "structural" typing. */
DEFPARAM (PARAM_VERIFY_CANONICAL_TYPES,
"verify-canonical-types",
"Whether to verify canonical types",
GCC_CANONICAL_TYPES_DEFAULT, 0, 1)
/*
Local variables:
mode:c

View File

@ -164,4 +164,6 @@ typedef enum compiler_param
PARAM_VALUE (PARAM_L1_CACHE_SIZE)
#define L1_CACHE_LINE_SIZE \
PARAM_VALUE (PARAM_L1_CACHE_LINE_SIZE)
#define VERIFY_CANONICAL_TYPES \
PARAM_VALUE (PARAM_VERIFY_CANONICAL_TYPES)
#endif /* ! GCC_PARAMS_H */

View File

@ -604,6 +604,11 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node),
TYPE_ALIAS_SET (node));
if (TYPE_STRUCTURAL_EQUALITY_P (node))
fprintf (file, " structural equality");
else
dump_addr (file, " canonical type ", TYPE_CANONICAL (node));
print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
if (INTEGRAL_TYPE_P (node) || TREE_CODE (node) == REAL_TYPE)

View File

@ -1782,6 +1782,11 @@ layout_type (tree type)
#else
TYPE_ALIGN (type) = MAX (TYPE_ALIGN (element), BITS_PER_UNIT);
#endif
if (!TYPE_SIZE (element))
/* We don't know the size of the underlying element type, so
our alignment calculations will be wrong, forcing us to
fall back on structural equality. */
SET_TYPE_STRUCTURAL_EQUALITY (type);
TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
TYPE_MODE (type) = BLKmode;
if (TYPE_SIZE (type) != 0

View File

@ -605,6 +605,7 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
TYPE_ALIGN (t) = BITS_PER_UNIT;
TYPE_USER_ALIGN (t) = 0;
TYPE_MAIN_VARIANT (t) = t;
TYPE_CANONICAL (t) = t;
/* Default to no attributes for type, but let target change that. */
TYPE_ATTRIBUTES (t) = NULL_TREE;
@ -3620,6 +3621,12 @@ build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
TYPE_REFERENCE_TO (ntype) = 0;
TYPE_ATTRIBUTES (ntype) = attribute;
if (TYPE_STRUCTURAL_EQUALITY_P (ttype))
SET_TYPE_STRUCTURAL_EQUALITY (ntype);
else
TYPE_CANONICAL (ntype)
= build_qualified_type (TYPE_CANONICAL (ttype), quals);
/* Create a new main variant of TYPE. */
TYPE_MAIN_VARIANT (ntype) = ntype;
TYPE_NEXT_VARIANT (ntype) = 0;
@ -3657,6 +3664,13 @@ build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
}
ntype = type_hash_canon (hashcode, ntype);
/* If the target-dependent attributes make NTYPE different from
its canonical type, we will need to use structural equality
checks for this qualified type. */
if (!targetm.comp_type_attributes (ntype, ttype))
SET_TYPE_STRUCTURAL_EQUALITY (ntype);
ttype = build_qualified_type (ntype, quals);
}
@ -4104,13 +4118,28 @@ build_qualified_type (tree type, int type_quals)
{
t = build_variant_type_copy (type);
set_type_quals (t, type_quals);
if (TYPE_STRUCTURAL_EQUALITY_P (type))
/* Propagate structural equality. */
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (type) != type)
/* Build the underlying canonical type, since it is different
from TYPE. */
TYPE_CANONICAL (t) = build_qualified_type (TYPE_CANONICAL (type),
type_quals);
else
/* T is its own canonical type. */
TYPE_CANONICAL (t) = t;
}
return t;
}
/* Create a new distinct copy of TYPE. The new type is made its own
MAIN_VARIANT. */
MAIN_VARIANT. If TYPE requires structural equality checks, the
resulting type requires structural equality checks; otherwise, its
TYPE_CANONICAL points to itself. */
tree
build_distinct_type_copy (tree type)
@ -4120,6 +4149,13 @@ build_distinct_type_copy (tree type)
TYPE_POINTER_TO (t) = 0;
TYPE_REFERENCE_TO (t) = 0;
/* Set the canonical type either to a new equivalence class, or
propagate the need for structural equality checks. */
if (TYPE_STRUCTURAL_EQUALITY_P (type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else
TYPE_CANONICAL (t) = t;
/* Make it its own variant. */
TYPE_MAIN_VARIANT (t) = t;
TYPE_NEXT_VARIANT (t) = 0;
@ -4127,8 +4163,11 @@ build_distinct_type_copy (tree type)
return t;
}
/* Create a new variant of TYPE, equivalent but distinct.
This is so the caller can modify it. */
/* Create a new variant of TYPE, equivalent but distinct. This is so
the caller can modify it. TYPE_CANONICAL for the return type will
be equivalent to TYPE_CANONICAL of TYPE, indicating that the types
are considered equal by the language itself (or that both types
require structural equality checks). */
tree
build_variant_type_copy (tree type)
@ -4136,6 +4175,10 @@ build_variant_type_copy (tree type)
tree t, m = TYPE_MAIN_VARIANT (type);
t = build_distinct_type_copy (type);
/* Since we're building a variant, assume that it is a non-semantic
variant. This also propagates TYPE_STRUCTURAL_EQUALITY_P. */
TYPE_CANONICAL (t) = TYPE_CANONICAL (type);
/* Add the new type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
@ -5237,6 +5280,13 @@ build_pointer_type_for_mode (tree to_type, enum machine_mode mode,
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
TYPE_POINTER_TO (to_type) = t;
if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (to_type) != to_type)
TYPE_CANONICAL (t)
= build_pointer_type_for_mode (TYPE_CANONICAL (to_type),
mode, can_alias_all);
/* Lay out the type. This function has many callers that are concerned
with expression-construction, and this simplifies them all. */
layout_type (t);
@ -5286,6 +5336,13 @@ build_reference_type_for_mode (tree to_type, enum machine_mode mode,
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
TYPE_REFERENCE_TO (to_type) = t;
if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (to_type) != to_type)
TYPE_CANONICAL (t)
= build_reference_type_for_mode (TYPE_CANONICAL (to_type),
mode, can_alias_all);
layout_type (t);
return t;
@ -5352,7 +5409,12 @@ build_index_type (tree maxval)
if (host_integerp (maxval, 1))
return type_hash_canon (tree_low_cst (maxval, 1), itype);
else
return itype;
{
/* Since we cannot hash this type, we need to compare it using
structural equality checks. */
SET_TYPE_STRUCTURAL_EQUALITY (itype);
return itype;
}
}
/* Builds a signed or unsigned integer type of precision PRECISION.
@ -5444,6 +5506,16 @@ build_array_type (tree elt_type, tree index_type)
t = type_hash_canon (hashcode, t);
if (save == t)
layout_type (t);
if (TYPE_CANONICAL (t) == t)
{
if (TYPE_STRUCTURAL_EQUALITY_P (elt_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (elt_type) != elt_type)
TYPE_CANONICAL (t)
= build_array_type (TYPE_CANONICAL (elt_type), index_type);
}
return t;
}
@ -5453,6 +5525,19 @@ build_array_type (tree elt_type, tree index_type)
if (!COMPLETE_TYPE_P (t))
layout_type (t);
if (TYPE_CANONICAL (t) == t)
{
if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
|| TYPE_STRUCTURAL_EQUALITY_P (index_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (elt_type) != elt_type
|| TYPE_CANONICAL (index_type) != index_type)
TYPE_CANONICAL (t)
= build_array_type (TYPE_CANONICAL (elt_type),
TYPE_CANONICAL (index_type));
}
return t;
}
@ -5494,6 +5579,9 @@ build_function_type (tree value_type, tree arg_types)
TREE_TYPE (t) = value_type;
TYPE_ARG_TYPES (t) = arg_types;
/* We don't have canonicalization of function types, yet. */
SET_TYPE_STRUCTURAL_EQUALITY (t);
/* If we already have such a type, use the old one. */
hashcode = iterative_hash_object (TYPE_HASH (value_type), hashcode);
hashcode = type_hash_list (arg_types, hashcode);
@ -5561,6 +5649,9 @@ build_method_type_directly (tree basetype,
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
/* We don't have canonicalization of method types yet. */
SET_TYPE_STRUCTURAL_EQUALITY (t);
/* If we already have such a type, use the old one. */
hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (rettype), hashcode);
@ -5612,6 +5703,18 @@ build_offset_type (tree basetype, tree type)
if (!COMPLETE_TYPE_P (t))
layout_type (t);
if (TYPE_CANONICAL (t) == t)
{
if (TYPE_STRUCTURAL_EQUALITY_P (basetype)
|| TYPE_STRUCTURAL_EQUALITY_P (type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (basetype) != basetype
|| TYPE_CANONICAL (type) != type)
TYPE_CANONICAL (t)
= build_offset_type (TYPE_CANONICAL (basetype),
TYPE_CANONICAL (type));
}
return t;
}
@ -5635,6 +5738,15 @@ build_complex_type (tree component_type)
if (!COMPLETE_TYPE_P (t))
layout_type (t);
if (TYPE_CANONICAL (t) == t)
{
if (TYPE_STRUCTURAL_EQUALITY_P (component_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (component_type) != component_type)
TYPE_CANONICAL (t)
= build_complex_type (TYPE_CANONICAL (component_type));
}
/* If we are writing Dwarf2 output we need to create a name,
since complex is a fundamental type. */
if ((write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
@ -6653,6 +6765,13 @@ make_vector_type (tree innertype, int nunits, enum machine_mode mode)
TYPE_READONLY (t) = TYPE_READONLY (innertype);
TYPE_VOLATILE (t) = TYPE_VOLATILE (innertype);
if (TYPE_STRUCTURAL_EQUALITY_P (innertype))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (innertype) != innertype
|| mode != VOIDmode)
TYPE_CANONICAL (t)
= make_vector_type (TYPE_CANONICAL (innertype), nunits, VOIDmode);
layout_type (t);
{
@ -6866,7 +6985,7 @@ build_common_tree_nodes_2 (int short_double)
declare the type to be __builtin_va_list. */
if (TREE_CODE (t) != RECORD_TYPE)
t = build_variant_type_copy (t);
va_list_type_node = t;
}
}

View File

@ -2005,6 +2005,27 @@ struct tree_block GTY(())
#define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant)
#define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant)
#define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context)
/* The "canonical" type for this type node, which can be used to
compare the type for equality with another type. If two types are
equal (based on the semantics of the language), then they will have
equivalent TYPE_CANONICAL entries.
As a special case, if TYPE_CANONICAL is NULL_TREE, then it cannot
be used for comparison against other types. Instead, the type is
said to require structural equality checks, described in
TYPE_STRUCTURAL_EQUALITY_P. */
#define TYPE_CANONICAL(NODE) (TYPE_CHECK (NODE)->type.canonical)
/* Indicates that the type node requires structural equality
checks. The compiler will need to look at the composition of the
type to determine whether it is equal to another type, rather than
just comparing canonical type pointers. For instance, we would need
to look at the return and parameter types of a FUNCTION_TYPE
node. */
#define TYPE_STRUCTURAL_EQUALITY_P(NODE) (TYPE_CANONICAL (NODE) == NULL_TREE)
/* Sets the TYPE_CANONICAL field to NULL_TREE, indicating that the
type node requires structural equality. */
#define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE)
#define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific)
/* For a VECTOR_TYPE node, this describes a different type which is emitted
@ -2205,6 +2226,7 @@ struct tree_type GTY(())
tree main_variant;
tree binfo;
tree context;
tree canonical;
HOST_WIDE_INT alias_set;
/* Points to a structure whose details depend on the language in use. */
struct lang_type *lang_specific;