Mark Mitchell - C++ PATCH: Fix PR c++/11105 (original) (raw)

This is the mail archive of the gcc-patches@gcc.gnu.orgmailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

This patch fixes PR c++/11105.

The fundamental problem was that we were trying to look up conversion operators by name when the only correct way to find them is by type. I've fixed that.

However, I've not changed the fact that we associated each conversion operator name with a type. Therefore, my fix changes FUNCTION in an conversion operator. That is pretty harmless since FUNCTION was already entirely bogus; it was neither the mangled nor the unmangled name of the operator, but rather the halfway-in-between "operator i" for a conversion to "int".

The next step would be to disassociate the name from the type; then we could just have FUNCTION be "operator int" which is the right answer.

Because this fix eliminates the possibility of a crash when using -fabi-version=1, I suspect some other PRs can now be closed as well. I'll troll through bugzilla a bit.

Tested on i686-pc-linux-gnu, applied on the mainline (and with minor variations) on the branch.

-- Mark Mitchell CodeSourcery, LLC mark@codesourcery.com

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 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.

Index: cp/cp-tree.h

RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v retrieving revision 1.852 diff -c -5 -p -r1.852 cp-tree.h *** cp/cp-tree.h 16 Jun 2003 13:15:35 -0000 1.852 --- cp/cp-tree.h 17 Jun 2003 16:53:51 -0000 *************** struct lang_decl GTY(()) *** 1854,1863 **** --- 1854,1868 ----
/* Nonzero if NODE is a user-defined conversion operator. / #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. */ #define DECL_TEMPLATE_CONV_FN_P(NODE)
(DECL_LANG_SPECIFIC (NODE)->decl_flags.template_conv_p) Index: cp/mangle.c

RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v retrieving revision 1.72 diff -c -5 -p -r1.72 mangle.c *** cp/mangle.c 17 Jun 2003 00:06:38 -0000 1.72 --- cp/mangle.c 17 Jun 2003 16:53:52 -0000 *************** static struct globals *** 100,114 **** varray_type substitutions;
/* 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;

} G;
--- 100,109 ---- *************** write_unqualified_name (const tree decl) *** 1004,1014 **** { tree fn_type = get_mostly_instantiated_function_type (decl); type = TREE_TYPE (fn_type); } else ! type = TREE_TYPE (DECL_NAME (decl)); write_conversion_operator_name (type); } else if (DECL_OVERLOADED_OPERATOR_P (decl)) { operator_name_info_t *oni; --- 999,1009 ---- { tree fn_type = get_mostly_instantiated_function_type (decl); type = TREE_TYPE (fn_type); } else ! type = DECL_CONV_FN_TYPE (decl); write_conversion_operator_name (type); } else if (DECL_OVERLOADED_OPERATOR_P (decl)) { operator_name_info_t oni; *************** write_template_param (const tree parm) *** 2248,2266 **** / NUMBER as it appears in the mangling is (-1)-indexed, with the earliest template param denoted by `'. */ 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 (''); - } }
/* ::= ::= / --- 2243,2252 ---- *************** mangle_thunk (tree fn_decl, const int th *** 2598,2641 **** if (DEBUG_MANGLE) fprintf (stderr, "mangle_thunk = %s\n\n", result); return get_identifier (result); }
/
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. */
tree mangle_conv_op_name_for_type (const tree type) { tree identifier; ! const char mangled_type; ! char op_name;
! /
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"); ! }
/
Set bits on the identifier so we know later it's a conversion. / IDENTIFIER_OPNAME_P (identifier) = 1; IDENTIFIER_TYPENAME_P (identifier) = 1; / Hang TYPE off the identifier so it can be found easily later when --- 2584,2638 ---- if (DEBUG_MANGLE) fprintf (stderr, "mangle_thunk = %s\n\n", result); 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. */
tree mangle_conv_op_name_for_type (const tree type) { + void **slot; tree identifier; ! char buffer[64];
! 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; IDENTIFIER_TYPENAME_P (identifier) = 1; / Hang TYPE off the identifier so it can be found easily later when Index: cp/search.c

RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v retrieving revision 1.264 diff -c -5 -p -r1.264 search.c *** cp/search.c 16 Jun 2003 21:41:09 -0000 1.264 --- cp/search.c 17 Jun 2003 16:53:53 -0000 *************** lookup_fnfields (tree xbasetype, tree na *** 1336,1438 **** return NULL_TREE;
return rval; }
/* 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);
! 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;
! #ifdef GATHER_STATISTICS ! n_calls_lookup_fnfields_1++; ! #endif /
GATHER_STATISTICS /
- /
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);

! n_outer_fields_searched++; #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; ! ! while (lo < hi) ! { ! i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS ! 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; ! } } }
return -1; }
/* DECL is the result of a qualified name lookup. QUALIFYING_SCOPE is --- 1336,1483 ---- return NULL_TREE;
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; ! tree *methods; ! tree tmp; ! int i; ! int len; ! ! if (!CLASS_TYPE_P (type)) ! return -1;
! method_vec = CLASSTYPE_METHOD_VEC (type);
! if (!method_vec) ! return -1; ! ! methods = &TREE_VEC_ELT (method_vec, 0); ! len = TREE_VEC_LENGTH (method_vec);
#ifdef GATHER_STATISTICS ! n_calls_lookup_fnfields_1++; #endif /* GATHER_STATISTICS */
! /* 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;
#ifdef GATHER_STATISTICS ! 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; } } + 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; }
/
DECL is the result of a qualified name lookup. QUALIFYING_SCOPE is Index: testsuite/g++.dg/abi/conv1.C

RCS file: testsuite/g++.dg/abi/conv1.C diff -N testsuite/g++.dg/abi/conv1.C *** testsuite/g++.dg/abi/conv1.C 20 Feb 2003 19:31:38 -0000 1.1 --- /dev/null 1 Jan 1970 00:00:00 -0000 *************** *** 1,13 **** - // { dg-options "-fabi-version=1" }


*** 0 **** --- 1,12 ---- + // { dg-options "-fabi-version=0" } + + template struct S { + struct I{}; + operator I* (); + }; + + template struct S2 : S { + operator typename S::I* (); + }; + + template struct S2; Index: testsuite/g++.dg/template/conv8.C

RCS file: testsuite/g++.dg/template/conv8.C diff -N testsuite/g++.dg/template/conv8.C *** /dev/null 1 Jan 1970 00:00:00 -0000 --- testsuite/g++.dg/template/conv8.C 17 Jun 2003 16:54:02 -0000 *************** *** 0 **** --- 1,12 ---- + // { dg-options "-fabi-version=1" } + + template struct S { + struct I{}; + operator I* (); + }; + + template struct S2 : S { + operator typename S::I* (); + }; + + template struct S2; Index: testsuite/g++.old-deja/g++.ext/pretty2.C

RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.ext/pretty2.C,v retrieving revision 1.7 diff -c -5 -p -r1.7 pretty2.C *** testsuite/g++.old-deja/g++.ext/pretty2.C 1 May 2003 02:02:39 -0000 1.7 --- testsuite/g++.old-deja/g++.ext/pretty2.C 17 Jun 2003 16:54:03 -0000


*** 1,7 **** // { dg-do run } ! // Copyright (C) 1999, 2000 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 21 Nov 1999 nathan@acm.org

// make sure FUNCTION and PRETTY_FUNCTION work in member functions

#include <stdio.h> --- 1,7 ---- // { dg-do run } ! // 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

#include <stdio.h> *************** X::operator int () *** 66,77 ****

printf ("conversion\n");
printf ("__FUNCTION__ %s\n", function);
printf ("__PRETTY_FUNCTION__ %s\n", pretty);

--- 66,75 ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]