From 8de08f4c8650d8b1b00901d0ada78ffd87a7cfa9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 4 Jul 2007 06:32:30 +0000 Subject: [PATCH] tree.c (maybe_canonicalize_argtypes): New. 2007-07-04 Douglas Gregor * tree.c (maybe_canonicalize_argtypes): New. (build_function_type): Set canonical type. (build_method_type_directly): Ditto. (reconstruct_complex_type): Rebuild the METHOD_TYPE node properly. 2007-07-04 Douglas Gregor * decl.c (build_ptrmemfunc_type): Always use structural equality tests when comparing pointer-to-member-function types, because the handling of TYPE_GET_PTRMEMFUNC_TYPE currently defeats canonical types. From-SVN: r126303 --- gcc/ChangeLog | 8 +++ gcc/cp/ChangeLog | 7 +++ gcc/cp/decl.c | 8 +-- gcc/tree.c | 126 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 133 insertions(+), 16 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dc785cb7d89..abeacc362ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2007-07-04 Douglas Gregor + + * tree.c (maybe_canonicalize_argtypes): New. + (build_function_type): Set canonical type. + (build_method_type_directly): Ditto. + (reconstruct_complex_type): Rebuild the METHOD_TYPE node + properly. + 2007-07-03 Andrew Pinski * tree-ssa-loop-ivopts.c (strip_offset_1): Treat POINTER_PLUS_EXPR diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 17b76c000f4..1621175b846 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2007-07-04 Douglas Gregor + + * decl.c (build_ptrmemfunc_type): Always use structural equality + tests when comparing pointer-to-member-function types, because the + handling of TYPE_GET_PTRMEMFUNC_TYPE currently defeats canonical + types. + 2007-07-03 Mark Mitchell * init.c (build_new): Tweak comment. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1fae5f8cd6a..630cec1295f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6602,10 +6602,10 @@ 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)); + /* Managing canonical types for the RECORD_TYPE behind a + pointer-to-member function is a nightmare, so use structural + equality for now. */ + SET_TYPE_STRUCTURAL_EQUALITY (t); return t; } diff --git a/gcc/tree.c b/gcc/tree.c index 72a2593ee5f..8feaf47ff52 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5647,6 +5647,82 @@ get_inner_array_type (tree array) return type; } +/* Computes the canonical argument types from the argument type list + ARGTYPES. + + ANY_STRUCTURAL_P points to a boolean that states whether any of the + other types that work with ARGTYPES (e.g., the return type of the + function) are structural. *ANY_STRUCTURAL_P will be set TRUE if any + of those types or any of the argument types in ARGTYPES are + structural. + + ANY_NONCANONICAL_P points to a boolean that states whether any of + the other types that work with ARGTYPES (e.g., the return type of + the function) are non-canonical type nodes. *ANY_NONCANONICAL_P + will be set TRUE if any of those types or any of the argument types + in ARGTYPES are non-canonical. + + Returns a canonical argument list, which may be ARGTYPES when the + canonical argument list is unneeded (i.e., *ANY_STRUCTURAL_P is + true) or would not differ from ARGTYPES. */ + +static tree +maybe_canonicalize_argtypes(tree argtypes, + bool *any_structural_p, + bool *any_noncanonical_p) +{ + tree arg; + bool any_noncanonical_argtypes_p = false; + + for (arg = argtypes; arg && !(*any_structural_p); arg = TREE_CHAIN (arg)) + { + if (!TREE_VALUE (arg) || TREE_VALUE (arg) == error_mark_node) + /* Fail gracefully by stating that the type is structural. */ + *any_structural_p = true; + else if (TYPE_STRUCTURAL_EQUALITY_P (TREE_VALUE (arg))) + *any_structural_p = true; + else if (TYPE_CANONICAL (TREE_VALUE (arg)) != TREE_VALUE (arg) + || TREE_PURPOSE (arg)) + /* If the argument has a default argument, we consider it + non-canonical even though the type itself is canonical. + That way, different variants of function and method types + with default arguments will all point to the variant with + no defaults as their canonical type. */ + any_noncanonical_argtypes_p = true; + } + + if (*any_structural_p) + return argtypes; + + if (any_noncanonical_argtypes_p) + { + /* Build the canonical list of argument types. */ + tree canon_argtypes = NULL_TREE; + bool is_void = false; + + for (arg = argtypes; arg; arg = TREE_CHAIN (arg)) + { + if (arg == void_list_node) + is_void = true; + else + canon_argtypes = tree_cons (NULL_TREE, + TYPE_CANONICAL (TREE_VALUE (arg)), + canon_argtypes); + } + + canon_argtypes = nreverse (canon_argtypes); + if (is_void) + canon_argtypes = chainon (canon_argtypes, void_list_node); + + /* There is a non-canonical type. */ + *any_noncanonical_p = true; + return canon_argtypes; + } + + /* The canonical argument types are the same as ARGTYPES. */ + return argtypes; +} + /* Construct, lay out and return the type of functions returning type VALUE_TYPE given arguments of types ARG_TYPES. @@ -5659,6 +5735,8 @@ build_function_type (tree value_type, tree arg_types) { tree t; hashval_t hashcode = 0; + bool any_structural_p, any_noncanonical_p; + tree canon_argtypes; if (TREE_CODE (value_type) == FUNCTION_TYPE) { @@ -5671,14 +5749,23 @@ 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); t = type_hash_canon (hashcode, t); + /* Set up the canonical type. */ + any_structural_p = TYPE_STRUCTURAL_EQUALITY_P (value_type); + any_noncanonical_p = TYPE_CANONICAL (value_type) != value_type; + canon_argtypes = maybe_canonicalize_argtypes (arg_types, + &any_structural_p, + &any_noncanonical_p); + if (any_structural_p) + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (any_noncanonical_p) + TYPE_CANONICAL (t) = build_function_type (TYPE_CANONICAL (value_type), + canon_argtypes); + if (!COMPLETE_TYPE_P (t)) layout_type (t); return t; @@ -5728,6 +5815,8 @@ build_method_type_directly (tree basetype, tree t; tree ptype; int hashcode = 0; + bool any_structural_p, any_noncanonical_p; + tree canon_argtypes; /* Make a node of the sort we want. */ t = make_node (METHOD_TYPE); @@ -5741,15 +5830,29 @@ 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); hashcode = type_hash_list (argtypes, hashcode); t = type_hash_canon (hashcode, t); + /* Set up the canonical type. */ + any_structural_p + = (TYPE_STRUCTURAL_EQUALITY_P (basetype) + || TYPE_STRUCTURAL_EQUALITY_P (rettype)); + any_noncanonical_p + = (TYPE_CANONICAL (basetype) != basetype + || TYPE_CANONICAL (rettype) != rettype); + canon_argtypes = maybe_canonicalize_argtypes (TREE_CHAIN (argtypes), + &any_structural_p, + &any_noncanonical_p); + if (any_structural_p) + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (any_noncanonical_p) + TYPE_CANONICAL (t) + = build_method_type_directly (TYPE_CANONICAL (basetype), + TYPE_CANONICAL (rettype), + canon_argtypes); if (!COMPLETE_TYPE_P (t)) layout_type (t); @@ -7329,15 +7432,14 @@ reconstruct_complex_type (tree type, tree bottom) } else if (TREE_CODE (type) == METHOD_TYPE) { - tree argtypes; inner = reconstruct_complex_type (TREE_TYPE (type), bottom); /* The build_method_type_directly() routine prepends 'this' to argument list, so we must compensate by getting rid of it. */ - argtypes = TYPE_ARG_TYPES (type); - outer = build_method_type_directly (TYPE_METHOD_BASETYPE (type), - inner, - TYPE_ARG_TYPES (type)); - TYPE_ARG_TYPES (outer) = argtypes; + outer + = build_method_type_directly + (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type))), + inner, + TREE_CHAIN (TYPE_ARG_TYPES (type))); } else return bottom;