mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-06 02:53:52 +08:00
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:
parent
8207b189e5
commit
ca90f3e1c7
@ -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.
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
191
gcc/cp/search.c
191
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 "" }
|
||||
};
|
12
gcc/testsuite/g++.dg/template/conv7.C
Normal file
12
gcc/testsuite/g++.dg/template/conv7.C
Normal 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>;
|
12
gcc/testsuite/g++.dg/template/conv8.C
Normal file
12
gcc/testsuite/g++.dg/template/conv8.C
Normal 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>;
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user