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
This commit is contained in:
Mark Mitchell 2003-06-17 16:58:19 +00:00 committed by Mark Mitchell
parent 8207b189e5
commit ca90f3e1c7
9 changed files with 208 additions and 128 deletions

View File

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

View File

@ -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. */

View File

@ -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);
if (conv_type_names == NULL)
conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL);
/* 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");
}
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;

View File

@ -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;
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++;
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);
/* 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));
for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
i < len && methods[i];
++i)
/* 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 = OVL_CURRENT (methods[i]);
if (DECL_NAME (tmp) == name)
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;
/* 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;
}
}
}
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;
}

View File

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

View File

@ -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 "" }
};

View File

@ -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>;

View File

@ -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>;

View File

@ -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;