2007-09-21 Jakub Jelinek PR c++/33506 * langhooks.h (struct lang_hooks_for_types): Add type_hash_eq field. * langhooks.c (lhd_type_hash_eq): New function. * langhooks-def.h (lhd_type_hash_eq): New prototype. (LANG_HOOKS_TYPE_HASH_EQ): Define. (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add LANG_HOOKS_TYPE_HASH_EQ. * tree.c (type_hash_eq): For FUNCTION_TYPE use lang_hooks.type.type_hash_eq in addition to generic tests. * cp-tree.h (cxx_type_hash_eq): New prototype. * cp-objcp-common.h (LANG_HOOKS_TYPE_HASH_EQ): Redefine. * tree.c (cxx_type_hash_eq): New function. * g++.dg/ext/attrib29.C: New test. --- gcc/langhooks.h.jj 2007-02-20 16:39:12.000000000 -0500 +++ gcc/langhooks.h 2007-09-22 03:46:10.000000000 -0400 @@ -148,6 +148,10 @@ struct lang_hooks_for_types firstprivate variables. */ void (*omp_firstprivatize_type_sizes) (struct gimplify_omp_ctx *, tree); + /* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes. + Called only after doing all language independent checks. */ + bool (*type_hash_eq) (tree, tree); + /* Nonzero if types that are identical are to be hashed so that only one copy is kept. If a language requires unique types for each user-specified type, such as Ada, this should be set to TRUE. */ --- gcc/langhooks.c.jj 2007-02-20 16:39:12.000000000 -0500 +++ gcc/langhooks.c 2007-09-22 03:46:10.000000000 -0400 @@ -411,6 +411,16 @@ lhd_tree_dump_type_quals (tree t) /* lang_hooks.expr_size: Determine the size of the value of an expression T in a language-specific way. Returns a tree for the size in bytes. */ +/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes. + Called only after doing all language independent checks. */ + +bool +lhd_type_hash_eq (tree typea ATTRIBUTE_UNUSED, + tree typeb ATTRIBUTE_UNUSED) +{ + return true; +} + tree lhd_expr_size (tree exp) { --- gcc/langhooks-def.h.jj 2007-02-20 16:39:13.000000000 -0500 +++ gcc/langhooks-def.h 2007-09-22 03:46:56.000000000 -0400 @@ -70,6 +70,7 @@ extern tree lhd_expr_size (tree); extern size_t lhd_tree_size (enum tree_code); extern HOST_WIDE_INT lhd_to_target_charset (HOST_WIDE_INT); extern tree lhd_expr_to_decl (tree, bool *, bool *, bool *); +extern bool lhd_type_hash_eq (tree, tree); /* Declarations of default tree inlining hooks. */ extern tree lhd_tree_inlining_walk_subtrees (tree *, int *, walk_tree_fn, @@ -220,6 +221,7 @@ extern tree lhd_make_node (enum tree_cod #define LANG_HOOKS_TYPE_MAX_SIZE lhd_return_null_tree #define LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES \ lhd_omp_firstprivatize_type_sizes +#define LANG_HOOKS_TYPE_HASH_EQ lhd_type_hash_eq #define LANG_HOOKS_HASH_TYPES true #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \ @@ -234,6 +236,7 @@ extern tree lhd_make_node (enum tree_cod LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \ LANG_HOOKS_TYPE_MAX_SIZE, \ LANG_HOOKS_OMP_FIRSTPRIVATIZE_TYPE_SIZES, \ + LANG_HOOKS_TYPE_HASH_EQ, \ LANG_HOOKS_HASH_TYPES \ } --- gcc/tree.c.jj 2007-04-03 07:18:26.000000000 -0400 +++ gcc/tree.c 2007-09-22 03:46:10.000000000 -0400 @@ -4168,17 +4168,21 @@ type_hash_eq (const void *va, const void TYPE_FIELDS (b->type)))); case FUNCTION_TYPE: - return (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type) - || (TYPE_ARG_TYPES (a->type) - && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST - && TYPE_ARG_TYPES (b->type) - && TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST - && type_list_equal (TYPE_ARG_TYPES (a->type), - TYPE_ARG_TYPES (b->type)))); + if (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type) + || (TYPE_ARG_TYPES (a->type) + && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST + && TYPE_ARG_TYPES (b->type) + && TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST + && type_list_equal (TYPE_ARG_TYPES (a->type), + TYPE_ARG_TYPES (b->type)))) + break; + return 0; default: return 0; } + + return lang_hooks.types.type_hash_eq (a->type, b->type); } /* Return the cached hash value. */ --- gcc/cp/cp-tree.h.jj 2007-06-26 07:57:09.000000000 -0400 +++ gcc/cp/cp-tree.h 2007-09-22 03:50:22.000000000 -0400 @@ -4421,7 +4421,8 @@ extern tree cp_add_pending_fn_decls (vo extern int cp_auto_var_in_fn_p (tree,tree); extern tree fold_if_not_in_template (tree); extern tree rvalue (tree); - +extern bool cxx_type_hash_eq (tree, tree); + /* in typeck.c */ extern int string_conv_p (tree, tree, int); extern tree cp_truthvalue_conversion (tree); --- gcc/cp/cp-objcp-common.h.jj 2007-02-20 16:37:34.000000000 -0500 +++ gcc/cp/cp-objcp-common.h 2007-09-22 03:49:38.000000000 -0400 @@ -85,6 +85,8 @@ extern tree objcp_tsubst_copy_and_build #define LANG_HOOKS_WRITE_GLOBALS lhd_do_nothing #undef LANG_HOOKS_COMDAT_GROUP #define LANG_HOOKS_COMDAT_GROUP cxx_comdat_group +#undef LANG_HOOKS_TYPE_HASH_EQ +#define LANG_HOOKS_TYPE_HASH_EQ cxx_type_hash_eq #undef LANG_HOOKS_FUNCTION_INIT #define LANG_HOOKS_FUNCTION_INIT cxx_push_function_context --- gcc/cp/tree.c.jj 2007-03-12 03:28:01.000000000 -0400 +++ gcc/cp/tree.c 2007-09-22 03:46:10.000000000 -0400 @@ -1959,6 +1959,22 @@ cp_build_type_attribute_variant (tree ty return new_type; } +/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes. + Called only after doing all language independent checks. Only + to check TYPE_RAISES_EXCEPTIONS for FUNCTION_TYPE, the rest is already + compared in type_hash_eq. */ + +bool +cxx_type_hash_eq (tree typea, tree typeb) +{ + if (TREE_CODE (typea) != FUNCTION_TYPE + || TYPE_RAISES_EXCEPTIONS (typea) == TYPE_RAISES_EXCEPTIONS (typeb)) + return true; + + return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea), + TYPE_RAISES_EXCEPTIONS (typeb), 1); +} + /* Apply FUNC to all language-specific sub-trees of TP in a pre-order traversal. Called from walk_tree. */ --- gcc/testsuite/g++.dg/ext/attrib29.C.jj 2007-09-22 03:46:10.000000000 -0400 +++ gcc/testsuite/g++.dg/ext/attrib29.C 2007-09-22 03:46:10.000000000 -0400 @@ -0,0 +1,10 @@ +// PR c++/33506 +// { dg-do compile } + +extern int f1 (char *) __attribute__ ((warn_unused_result)); +extern int f2 (char *) throw () __attribute__ ((warn_unused_result)); +extern int f2 (char *) throw (); + +extern int f3 (char *) __attribute__ ((nonnull (1))); +extern int f4 (char *) throw () __attribute__ ((nonnull (1))); +extern int f4 (char *) throw ();