Commit ca90f3e1 by Mark Mitchell Committed by Mark Mitchell

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
parent 8207b189
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> 2003-06-17 Andreas Jaeger <aj@suse.de>
* except.c: Remove duplicate declaration of push_eh_cleanup. * except.c: Remove duplicate declaration of push_eh_cleanup.
......
...@@ -1856,6 +1856,11 @@ struct lang_decl GTY(()) ...@@ -1856,6 +1856,11 @@ struct lang_decl GTY(())
#define DECL_CONV_FN_P(NODE) \ #define DECL_CONV_FN_P(NODE) \
(IDENTIFIER_TYPENAME_P (DECL_NAME (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 /* Nonzero if NODE, which is a TEMPLATE_DECL, is a template
conversion operator to a type dependent on the innermost template conversion operator to a type dependent on the innermost template
args. */ args. */
......
...@@ -102,11 +102,6 @@ static struct globals ...@@ -102,11 +102,6 @@ static struct globals
/* The entity that is being mangled. */ /* The entity that is being mangled. */
tree entity; 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 /* True if the mangling will be different in a future version of the
ABI. */ ABI. */
bool need_abi_warning; bool need_abi_warning;
...@@ -1006,7 +1001,7 @@ write_unqualified_name (const tree decl) ...@@ -1006,7 +1001,7 @@ write_unqualified_name (const tree decl)
type = TREE_TYPE (fn_type); type = TREE_TYPE (fn_type);
} }
else else
type = TREE_TYPE (DECL_NAME (decl)); type = DECL_CONV_FN_TYPE (decl);
write_conversion_operator_name (type); write_conversion_operator_name (type);
} }
else if (DECL_OVERLOADED_OPERATOR_P (decl)) else if (DECL_OVERLOADED_OPERATOR_P (decl))
...@@ -2250,15 +2245,6 @@ write_template_param (const tree parm) ...@@ -2250,15 +2245,6 @@ write_template_param (const tree parm)
if (parm_index > 0) if (parm_index > 0)
write_unsigned_number (parm_index - 1); write_unsigned_number (parm_index - 1);
write_char ('_'); 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> /* <template-template-param>
...@@ -2600,6 +2586,28 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset, ...@@ -2600,6 +2586,28 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
return get_identifier (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 /* Return an identifier for the mangled unqualified name for a
conversion operator to TYPE. This mangling is not specified by the conversion operator to TYPE. This mangling is not specified by the
ABI spec; it is only used internally. */ ABI spec; it is only used internally. */
...@@ -2607,33 +2615,22 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset, ...@@ -2607,33 +2615,22 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
tree tree
mangle_conv_op_name_for_type (const tree type) mangle_conv_op_name_for_type (const tree type)
{ {
void **slot;
tree identifier; tree identifier;
const char *mangled_type; char buffer[64];
char *op_name;
/* Build the internal mangling for TYPE. */ if (conv_type_names == NULL)
G.internal_mangling_p = true; conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL);
mangled_type = mangle_type_string (type);
G.internal_mangling_p = false; slot = htab_find_slot_with_hash (conv_type_names, type,
htab_hash_pointer (type), INSERT);
/* Allocate a temporary buffer for the complete name. */ if (*slot)
op_name = concat ("operator ", mangled_type, NULL); return TREE_VALUE ((tree) *slot);
/* Find or create an identifier. */
identifier = get_identifier (op_name); /* Create a unique name corresponding to TYPE. */
/* Done with the temporary buffer. */ sprintf (buffer, "operator %d\n", htab_elements (conv_type_names));
free (op_name); identifier = get_identifier (buffer);
*slot = build_tree_list (type, identifier);
/* 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. */ /* Set bits on the identifier so we know later it's a conversion. */
IDENTIFIER_OPNAME_P (identifier) = 1; IDENTIFIER_OPNAME_P (identifier) = 1;
......
...@@ -1338,99 +1338,144 @@ lookup_fnfields (tree xbasetype, tree name, int protect) ...@@ -1338,99 +1338,144 @@ lookup_fnfields (tree xbasetype, tree name, int protect)
return rval; 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 /* 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. */ the method vector with name NAME, or -1 is no such field exists. */
int int
lookup_fnfields_1 (tree type, tree name) lookup_fnfields_1 (tree type, tree name)
{ {
tree method_vec = (CLASS_TYPE_P (type) tree method_vec;
? CLASSTYPE_METHOD_VEC (type) tree *methods;
: NULL_TREE); tree tmp;
int i;
int len;
if (method_vec != 0) if (!CLASS_TYPE_P (type))
{ return -1;
register int i;
register tree *methods = &TREE_VEC_ELT (method_vec, 0);
int len = TREE_VEC_LENGTH (method_vec);
tree tmp;
#ifdef GATHER_STATISTICS method_vec = CLASSTYPE_METHOD_VEC (type);
n_calls_lookup_fnfields_1++;
#endif /* GATHER_STATISTICS */ 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 #ifdef GATHER_STATISTICS
n_outer_fields_searched++; n_calls_lookup_fnfields_1++;
#endif /* GATHER_STATISTICS */ #endif /* GATHER_STATISTICS */
tmp = OVL_CURRENT (methods[i]); /* Constructors are first... */
if (DECL_NAME (tmp) == name) if (name == ctor_identifier)
return i; return (methods[CLASSTYPE_CONSTRUCTOR_SLOT]
? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
/* If the type is complete and we're past the conversion ops, /* and destructors are second. */
switch to binary search. */ if (name == dtor_identifier)
if (! DECL_CONV_FN_P (tmp) return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
&& COMPLETE_TYPE_P (type)) ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
{ if (IDENTIFIER_TYPENAME_P (name))
int lo = i + 1, hi = len; 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) while (lo < hi)
{ {
i = (lo + hi) / 2; i = (lo + hi) / 2;
#ifdef GATHER_STATISTICS #ifdef GATHER_STATISTICS
n_outer_fields_searched++; n_outer_fields_searched++;
#endif /* GATHER_STATISTICS */ #endif /* GATHER_STATISTICS */
tmp = methods[i]; tmp = methods[i];
/* This slot may be empty; we allocate more slots /* This slot may be empty; we allocate more slots than we
than we need. In that case, the entry we're need. In that case, the entry we're looking for is
looking for is closer to the beginning of the closer to the beginning of the list. */
list. */ if (tmp)
if (tmp) tmp = DECL_NAME (OVL_CURRENT (tmp));
tmp = DECL_NAME (OVL_CURRENT (tmp)); if (!tmp || tmp > name)
if (!tmp || tmp > name) hi = i;
hi = i; else if (tmp < name)
else if (tmp < name) lo = i + 1;
lo = i + 1; else
else return i;
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;
}
} }
} }
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; return -1;
} }
......
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> 2003-06-17 Janis Johnson <janis187@us.ibm.com>
* gcc.dg/compat/compat-common.h (DEBUG_INIT): New. * gcc.dg/compat/compat-common.h (DEBUG_INIT): New.
......
// { 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 "" }
};
// { 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>;
// { 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>;
// { dg-do run } // { 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> // Contributed by Nathan Sidwell 21 Nov 1999 <nathan@acm.org>
// make sure __FUNCTION__ and __PRETTY_FUNCTION__ work in member functions // make sure __FUNCTION__ and __PRETTY_FUNCTION__ work in member functions
...@@ -68,8 +68,6 @@ X::operator int () ...@@ -68,8 +68,6 @@ X::operator int ()
printf ("__FUNCTION__ %s\n", function); printf ("__FUNCTION__ %s\n", function);
printf ("__PRETTY_FUNCTION__ %s\n", pretty); printf ("__PRETTY_FUNCTION__ %s\n", pretty);
if (strcmp (function, "operator i"))
bad = true;
if (strcmp (pretty, "X::operator int()")) if (strcmp (pretty, "X::operator int()"))
bad = true; bad = true;
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment