diff options
author | Mark Mitchell <mark@codesourcery.com> | 2003-06-17 16:58:19 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2003-06-17 16:58:19 +0000 |
commit | ca90f3e1c758d9efb6c8ba658a66675c3c36c6d4 (patch) | |
tree | 9158221fab15fe3ae9e6c048a33b2f599faa86c7 | |
parent | 8207b189e50ec5350d3ab72b397ee139282b4e9d (diff) | |
download | gcc-ca90f3e1c758d9efb6c8ba658a66675c3c36c6d4.zip gcc-ca90f3e1c758d9efb6c8ba658a66675c3c36c6d4.tar.gz gcc-ca90f3e1c758d9efb6c8ba658a66675c3c36c6d4.tar.bz2 |
re PR c++/11105 ([3.3/3.4 regression of sorts] ICE in mangle_conv_op_name_for_type)
PR c++/11105
* cp-tree.h (DECL_CONV_FN_TYPE): New method.
* mangle.c (struct globals): Remove internal_mangling_p.
(write_unqualified_name): Use DECL_CONV_FN_TYPE.
(write_template_parm): Don't write out the level number.
(conv_type_names): New variable.
(hash_type): New function.
(compare_type): Likewise.
(mangle_conv_op_name_for_type): Don't try to mangle conversion
operator names.
* search.c (lookup_conversion_operator): New function.
(lookup_fnfields_1): Use it.
PR c++/11105
* g++.dg/abi/conv1.C: Remove it.
* g++.dg/template/conv7.C: New test.
* g++.dg/template/conv8.C: Likewise.
* g++.old-deja/g++.ext/pretty2.C: Do not test __FUNCTION__ for a
conversion operator.
From-SVN: r68095
-rw-r--r-- | gcc/cp/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 77 | ||||
-rw-r--r-- | gcc/cp/search.c | 193 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/conv1.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv7.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/conv8.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.ext/pretty2.C | 4 |
9 files changed, 210 insertions, 130 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 63eb324..a3585fc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2003-06-17 Mark Mitchell <mark@codesourcery.com> + + PR c++/11105 + * cp-tree.h (DECL_CONV_FN_TYPE): New method. + * mangle.c (struct globals): Remove internal_mangling_p. + (write_unqualified_name): Use DECL_CONV_FN_TYPE. + (write_template_parm): Don't write out the level number. + (conv_type_names): New variable. + (hash_type): New function. + (compare_type): Likewise. + (mangle_conv_op_name_for_type): Don't try to mangle conversion + operator names. + * search.c (lookup_conversion_operator): New function. + (lookup_fnfields_1): Use it. + 2003-06-17 Andreas Jaeger <aj@suse.de> * except.c: Remove duplicate declaration of push_eh_cleanup. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6ed177e..aeae231 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1856,6 +1856,11 @@ struct lang_decl GTY(()) #define DECL_CONV_FN_P(NODE) \ (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE))) +/* If FN is a conversion operator, the type to which it converts. + Otherwise, NULL_TREE. */ +#define DECL_CONV_FN_TYPE(FN) \ + (DECL_CONV_FN_P (FN) ? TREE_TYPE (DECL_NAME (FN)) : NULL_TREE) + /* Nonzero if NODE, which is a TEMPLATE_DECL, is a template conversion operator to a type dependent on the innermost template args. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index c0d31ba..4c53662 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -102,11 +102,6 @@ static struct globals /* The entity that is being mangled. */ tree entity; - /* We are mangling an internal symbol. It is important to keep those - involving template parmeters distinct by distinguishing their level - and, for non-type parms, their type. */ - bool internal_mangling_p; - /* True if the mangling will be different in a future version of the ABI. */ bool need_abi_warning; @@ -1006,7 +1001,7 @@ write_unqualified_name (const tree decl) type = TREE_TYPE (fn_type); } else - type = TREE_TYPE (DECL_NAME (decl)); + type = DECL_CONV_FN_TYPE (decl); write_conversion_operator_name (type); } else if (DECL_OVERLOADED_OPERATOR_P (decl)) @@ -2250,15 +2245,6 @@ write_template_param (const tree parm) if (parm_index > 0) write_unsigned_number (parm_index - 1); write_char ('_'); - if (G.internal_mangling_p) - { - if (parm_level > 0) - write_unsigned_number (parm_level - 1); - write_char ('_'); - if (parm_type) - write_type (parm_type); - write_char ('_'); - } } /* <template-template-param> @@ -2600,6 +2586,28 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset, return get_identifier (result); } +/* This hash table maps TYPEs to the IDENTIFIER for a conversion + operator to TYPE. The nodes are TREE_LISTs whose TREE_PURPOSE is + the TYPE and whose TREE_VALUE is the IDENTIFIER. */ + +static GTY ((param_is (union tree_node))) htab_t conv_type_names; + +/* Hash a node (VAL1) in the table. */ + +static hashval_t +hash_type (const void *val) +{ + return htab_hash_pointer (TREE_PURPOSE (*((tree *) val))); +} + +/* Compare VAL1 (a node in the table) with VAL2 (a TYPE). */ + +static int +compare_type (const void *val1, const void *val2) +{ + return TREE_PURPOSE ((tree) val1) == (tree) val2; +} + /* Return an identifier for the mangled unqualified name for a conversion operator to TYPE. This mangling is not specified by the ABI spec; it is only used internally. */ @@ -2607,33 +2615,22 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset, tree mangle_conv_op_name_for_type (const tree type) { + void **slot; tree identifier; - const char *mangled_type; - char *op_name; + char buffer[64]; - /* Build the internal mangling for TYPE. */ - G.internal_mangling_p = true; - mangled_type = mangle_type_string (type); - G.internal_mangling_p = false; - - /* Allocate a temporary buffer for the complete name. */ - op_name = concat ("operator ", mangled_type, NULL); - /* Find or create an identifier. */ - identifier = get_identifier (op_name); - /* Done with the temporary buffer. */ - free (op_name); - - /* It had better be a unique mangling for the type. */ - if (IDENTIFIER_TYPENAME_P (identifier) - && !same_type_p (type, TREE_TYPE (identifier))) - { - /* In G++ 3.2, the name mangling scheme was ambiguous. In later - versions of the ABI, this problem has been fixed. */ - if (abi_version_at_least (2)) - abort (); - error ("due to a defect in the G++ 3.2 ABI, G++ has assigned the " - "same mangled name to two different types"); - } + if (conv_type_names == NULL) + conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL); + + slot = htab_find_slot_with_hash (conv_type_names, type, + htab_hash_pointer (type), INSERT); + if (*slot) + return TREE_VALUE ((tree) *slot); + + /* Create a unique name corresponding to TYPE. */ + sprintf (buffer, "operator %d\n", htab_elements (conv_type_names)); + identifier = get_identifier (buffer); + *slot = build_tree_list (type, identifier); /* Set bits on the identifier so we know later it's a conversion. */ IDENTIFIER_OPNAME_P (identifier) = 1; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 0cc769e..3df6f73 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1338,99 +1338,144 @@ lookup_fnfields (tree xbasetype, tree name, int protect) return rval; } +/* Return the index in the CLASSTYPE_METHOD_VEC for CLASS_TYPE + corresponding to "operator TYPE ()", or -1 if there is no such + operator. Only CLASS_TYPE itself is searched; this routine does + not scan the base classes of CLASS_TYPE. */ + +static int +lookup_conversion_operator (tree class_type, tree type) +{ + int pass; + int i; + + tree methods = CLASSTYPE_METHOD_VEC (class_type); + + for (pass = 0; pass < 2; ++pass) + for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; + i < TREE_VEC_LENGTH (methods); + ++i) + { + tree fn = TREE_VEC_ELT (methods, i); + /* The size of the vector may have some unused slots at the + end. */ + if (!fn) + break; + + /* All the conversion operators come near the beginning of the + class. Therefore, if FN is not a conversion operator, there + is no matching conversion operator in CLASS_TYPE. */ + fn = OVL_CURRENT (fn); + if (!DECL_CONV_FN_P (fn)) + break; + + if (pass == 0) + { + /* On the first pass we only consider exact matches. If + the types match, this slot is the one where the right + conversion operators can be found. */ + if (TREE_CODE (fn) != TEMPLATE_DECL + && same_type_p (DECL_CONV_FN_TYPE (fn), type)) + return i; + } + else + { + /* On the second pass we look for template conversion + operators. It may be possible to instantiate the + template to get the type desired. All of the template + conversion operators share a slot. By looking for + templates second we ensure that specializations are + preferred over templates. */ + if (TREE_CODE (fn) == TEMPLATE_DECL) + return i; + } + } + + return -1; +} + /* TYPE is a class type. Return the index of the fields within the method vector with name NAME, or -1 is no such field exists. */ int lookup_fnfields_1 (tree type, tree name) { - tree method_vec = (CLASS_TYPE_P (type) - ? CLASSTYPE_METHOD_VEC (type) - : NULL_TREE); + tree method_vec; + tree *methods; + tree tmp; + int i; + int len; - if (method_vec != 0) - { - register int i; - register tree *methods = &TREE_VEC_ELT (method_vec, 0); - int len = TREE_VEC_LENGTH (method_vec); - tree tmp; + if (!CLASS_TYPE_P (type)) + return -1; -#ifdef GATHER_STATISTICS - n_calls_lookup_fnfields_1++; -#endif /* GATHER_STATISTICS */ + method_vec = CLASSTYPE_METHOD_VEC (type); + + if (!method_vec) + return -1; + + methods = &TREE_VEC_ELT (method_vec, 0); + len = TREE_VEC_LENGTH (method_vec); - /* Constructors are first... */ - if (name == ctor_identifier) - return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] - ? CLASSTYPE_CONSTRUCTOR_SLOT : -1); - /* and destructors are second. */ - if (name == dtor_identifier) - return (methods[CLASSTYPE_DESTRUCTOR_SLOT] - ? CLASSTYPE_DESTRUCTOR_SLOT : -1); - - for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; - i < len && methods[i]; - ++i) - { #ifdef GATHER_STATISTICS - n_outer_fields_searched++; + n_calls_lookup_fnfields_1++; #endif /* GATHER_STATISTICS */ - tmp = OVL_CURRENT (methods[i]); - if (DECL_NAME (tmp) == name) - return i; - - /* If the type is complete and we're past the conversion ops, - switch to binary search. */ - if (! DECL_CONV_FN_P (tmp) - && COMPLETE_TYPE_P (type)) - { - int lo = i + 1, hi = len; + /* Constructors are first... */ + if (name == ctor_identifier) + return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] + ? CLASSTYPE_CONSTRUCTOR_SLOT : -1); + /* and destructors are second. */ + if (name == dtor_identifier) + return (methods[CLASSTYPE_DESTRUCTOR_SLOT] + ? CLASSTYPE_DESTRUCTOR_SLOT : -1); + if (IDENTIFIER_TYPENAME_P (name)) + return lookup_conversion_operator (type, TREE_TYPE (name)); + + /* Skip the conversion operators. */ + i = CLASSTYPE_FIRST_CONVERSION_SLOT; + while (i < len && methods[i] && DECL_CONV_FN_P (OVL_CURRENT (methods[i]))) + i++; + + /* If the type is complete, use binary search. */ + if (COMPLETE_TYPE_P (type)) + { + int lo = i; + int hi = len; - while (lo < hi) - { - i = (lo + hi) / 2; + while (lo < hi) + { + i = (lo + hi) / 2; #ifdef GATHER_STATISTICS - n_outer_fields_searched++; + n_outer_fields_searched++; #endif /* GATHER_STATISTICS */ - tmp = methods[i]; - /* This slot may be empty; we allocate more slots - than we need. In that case, the entry we're - looking for is closer to the beginning of the - list. */ - if (tmp) - tmp = DECL_NAME (OVL_CURRENT (tmp)); - if (!tmp || tmp > name) - hi = i; - else if (tmp < name) - lo = i + 1; - else - return i; - } - break; - } - } - - /* If we didn't find it, it might have been a template - conversion operator to a templated type. If there are any, - such template conversion operators will all be overloaded on - the first conversion slot. (Note that we don't look for this - case above so that we will always find specializations - first.) */ - if (IDENTIFIER_TYPENAME_P (name)) - { - i = CLASSTYPE_FIRST_CONVERSION_SLOT; - if (i < len && methods[i]) - { - tmp = OVL_CURRENT (methods[i]); - if (TREE_CODE (tmp) == TEMPLATE_DECL - && DECL_TEMPLATE_CONV_FN_P (tmp)) - return i; - } + tmp = methods[i]; + /* This slot may be empty; we allocate more slots than we + need. In that case, the entry we're looking for is + closer to the beginning of the list. */ + if (tmp) + tmp = DECL_NAME (OVL_CURRENT (tmp)); + if (!tmp || tmp > name) + hi = i; + else if (tmp < name) + lo = i + 1; + else + return i; } } + else + for (; i < len && methods[i]; ++i) + { +#ifdef GATHER_STATISTICS + n_outer_fields_searched++; +#endif /* GATHER_STATISTICS */ + + tmp = OVL_CURRENT (methods[i]); + if (DECL_NAME (tmp) == name) + return i; + } return -1; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8a2b084..9c1fcd2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2003-06-17 Mark Mitchell <mark@codesourcery.com> + + PR c++/11105 + * g++.dg/abi/conv1.C: Remove it. + * g++.dg/template/conv7.C: New test. + * g++.dg/template/conv8.C: Likewise. + * g++.old-deja/g++.ext/pretty2.C: Do not test __FUNCTION__ for a + conversion operator. + 2003-06-17 Janis Johnson <janis187@us.ibm.com> * gcc.dg/compat/compat-common.h (DEBUG_INIT): New. diff --git a/gcc/testsuite/g++.dg/abi/conv1.C b/gcc/testsuite/g++.dg/abi/conv1.C deleted file mode 100644 index fdedea2..0000000 --- a/gcc/testsuite/g++.dg/abi/conv1.C +++ /dev/null @@ -1,13 +0,0 @@ -// { dg-options "-fabi-version=1" } - -template<class T1> -struct A { - typedef typename T1::X X; - operator X() const; -}; - -template <class T0, class T1 > -struct B { - typedef typename T1::X X; - operator X() const; // { dg-error "" } -}; diff --git a/gcc/testsuite/g++.dg/template/conv7.C b/gcc/testsuite/g++.dg/template/conv7.C new file mode 100644 index 0000000..86758b3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/conv7.C @@ -0,0 +1,12 @@ +// { dg-options "-fabi-version=0" } + +template <typename T> struct S { + struct I{}; + operator I* (); +}; + +template <typename T> struct S2 : S<T> { + operator typename S<T>::I* (); +}; + +template struct S2<int>; diff --git a/gcc/testsuite/g++.dg/template/conv8.C b/gcc/testsuite/g++.dg/template/conv8.C new file mode 100644 index 0000000..96f3b98 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/conv8.C @@ -0,0 +1,12 @@ +// { dg-options "-fabi-version=1" } + +template <typename T> struct S { + struct I{}; + operator I* (); +}; + +template <typename T> struct S2 : S<T> { + operator typename S<T>::I* (); +}; + +template struct S2<int>; diff --git a/gcc/testsuite/g++.old-deja/g++.ext/pretty2.C b/gcc/testsuite/g++.old-deja/g++.ext/pretty2.C index 834ffa5..c309dc8 100644 --- a/gcc/testsuite/g++.old-deja/g++.ext/pretty2.C +++ b/gcc/testsuite/g++.old-deja/g++.ext/pretty2.C @@ -1,5 +1,5 @@ // { dg-do run } -// Copyright (C) 1999, 2000 Free Software Foundation, Inc. +// Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 21 Nov 1999 <nathan@acm.org> // make sure __FUNCTION__ and __PRETTY_FUNCTION__ work in member functions @@ -68,8 +68,6 @@ X::operator int () printf ("__FUNCTION__ %s\n", function); printf ("__PRETTY_FUNCTION__ %s\n", pretty); - if (strcmp (function, "operator i")) - bad = true; if (strcmp (pretty, "X::operator int()")) bad = true; return 0; |