+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.
#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. */
/* 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;
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))
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>
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;
- 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;
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;
}
+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.
+++ /dev/null
-// { 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 "" }
-};
--- /dev/null
+// { 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>;
--- /dev/null
+// { 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 }
-// 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
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;