/* Name mangling for the 3.0 C++ ABI.
- Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Written by Alex Samuel <sameul@codesourcery.com>
This file is part of GCC.
#include "obstack.h"
#include "toplev.h"
#include "varray.h"
+#include "flags.h"
+#include "target.h"
/* Debugging support. */
&& (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
/* Things we only need one of. This module is not reentrant. */
-static struct globals
+typedef struct globals GTY(())
{
- /* The name in which we're building the mangled name. */
- struct obstack name_obstack;
-
/* An array of the current substitution candidates, in the order
we've seen them. */
varray_type substitutions;
/* The entity that is being mangled. */
- tree entity;
+ tree GTY ((skip)) entity;
/* True if the mangling will be different in a future version of the
ABI. */
bool need_abi_warning;
-} G;
+} globals;
+
+static GTY (()) globals G;
+
+/* The obstack on which we build mangled names. */
+static struct obstack *mangle_obstack;
+
+/* The obstack on which we build mangled names that are not going to
+ be IDENTIFIER_NODEs. */
+static struct obstack name_obstack;
+
+/* The first object on the name_obstack; we use this to free memory
+ allocated on the name_obstack. */
+static void *name_base;
+
+/* An incomplete mangled name. There will be no NUL terminator. If
+ there is no incomplete mangled name, this variable is NULL. */
+static char *partially_mangled_name;
+
+/* The number of characters in the PARTIALLY_MANGLED_NAME. */
+static size_t partially_mangled_name_len;
/* Indices into subst_identifiers. These are identifiers used in
special substitution rules. */
/* Functions for emitting mangled representations of things. */
-static void write_mangled_name (const tree);
+static void write_mangled_name (const tree, bool);
static void write_encoding (const tree);
static void write_name (tree, const int);
static void write_unscoped_name (const tree);
/* Control functions. */
-static inline void start_mangling (const tree);
+static inline void start_mangling (const tree, bool);
static inline const char *finish_mangling (const bool);
static tree mangle_special_for_type (const tree, const char *);
/* Append a single character to the end of the mangled
representation. */
#define write_char(CHAR) \
- obstack_1grow (&G.name_obstack, (CHAR))
+ obstack_1grow (mangle_obstack, (CHAR))
/* Append a sized buffer to the end of the mangled representation. */
#define write_chars(CHAR, LEN) \
- obstack_grow (&G.name_obstack, (CHAR), (LEN))
+ obstack_grow (mangle_obstack, (CHAR), (LEN))
/* Append a NUL-terminated string to the end of the mangled
representation. */
#define write_string(STRING) \
- obstack_grow (&G.name_obstack, (STRING), strlen (STRING))
+ obstack_grow (mangle_obstack, (STRING), strlen (STRING))
/* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
same purpose (context, which may be a type) and value (template
#define write_unsigned_number(NUMBER) \
write_number ((NUMBER), /*unsigned_p=*/1, 10)
+/* Save the current (incomplete) mangled name and release the obstack
+ storage holding it. This function should be used during mangling
+ when making a call that could result in a call to get_identifier,
+ as such a call will clobber the same obstack being used for
+ mangling. This function may not be called twice without an
+ intervening call to restore_partially_mangled_name. */
+
+static void
+save_partially_mangled_name (void)
+{
+ if (mangle_obstack == &ident_hash->stack)
+ {
+ gcc_assert (!partially_mangled_name);
+ partially_mangled_name_len = obstack_object_size (mangle_obstack);
+ partially_mangled_name = xmalloc (partially_mangled_name_len);
+ memcpy (partially_mangled_name, obstack_base (mangle_obstack),
+ partially_mangled_name_len);
+ obstack_free (mangle_obstack, obstack_finish (mangle_obstack));
+ }
+}
+
+/* Restore the incomplete mangled name saved with
+ save_partially_mangled_name. */
+
+static void
+restore_partially_mangled_name (void)
+{
+ if (partially_mangled_name)
+ {
+ obstack_grow (mangle_obstack, partially_mangled_name,
+ partially_mangled_name_len);
+ free (partially_mangled_name);
+ partially_mangled_name = NULL;
+ }
+}
+
/* If DECL is a template instance, return nonzero and, if
TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
Otherwise return zero. */
for (i = VARRAY_ACTIVE_SIZE (G.substitutions); --i >= 0; )
{
const tree candidate = VARRAY_TREE (G.substitutions, i);
- if ((DECL_P (node)
- && node == candidate)
- || (TYPE_P (node)
- && TYPE_P (candidate)
- && same_type_p (node, candidate)))
- abort ();
+
+ gcc_assert (!(DECL_P (node) && node == candidate));
+ gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
+ && same_type_p (node, candidate)));
}
}
#endif /* ENABLE_CHECKING */
}
-/* <mangled-name> ::= _Z <encoding> */
+/* TOP_LEVEL is true, if this is being called at outermost level of
+ mangling. It should be false when mangling a decl appearing in an
+ expression within some other mangling.
+
+ <mangled-name> ::= _Z <encoding> */
-static inline void
-write_mangled_name (const tree decl)
+static void
+write_mangled_name (const tree decl, bool top_level)
{
MANGLE_TRACE_TREE ("mangled-name", decl);
- if (DECL_LANG_SPECIFIC (decl)
- && DECL_EXTERN_C_FUNCTION_P (decl)
- && ! DECL_OVERLOADED_OPERATOR_P (decl))
- /* The standard notes:
- "The <encoding> of an extern "C" function is treated like
- global-scope data, i.e. as its <source-name> without a type."
- We cannot write overloaded operators that way though,
- because it contains characters invalid in assembler. */
- write_source_name (DECL_NAME (decl));
+ if (/* The names of `extern "C"' functions are not mangled. */
+ DECL_EXTERN_C_FUNCTION_P (decl)
+ /* But overloaded operator names *are* mangled. */
+ && !DECL_OVERLOADED_OPERATOR_P (decl))
+ {
+ unmangled_name:;
+
+ if (top_level)
+ write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
+ else
+ {
+ /* The standard notes: "The <encoding> of an extern "C"
+ function is treated like global-scope data, i.e. as its
+ <source-name> without a type." We cannot write
+ overloaded operators that way though, because it contains
+ characters invalid in assembler. */
+ if (abi_version_at_least (2))
+ write_string ("_Z");
+ else
+ G.need_abi_warning = true;
+ write_source_name (DECL_NAME (decl));
+ }
+ }
+ else if (TREE_CODE (decl) == VAR_DECL
+ /* The names of global variables aren't mangled. */
+ && (CP_DECL_CONTEXT (decl) == global_namespace
+ /* And neither are `extern "C"' variables. */
+ || DECL_EXTERN_C_P (decl)))
+ {
+ if (top_level || abi_version_at_least (2))
+ goto unmangled_name;
+ else
+ {
+ G.need_abi_warning = true;
+ goto mangled_name;
+ }
+ }
else
- /* C++ name; needs to be mangled. */
{
+ mangled_name:;
write_string ("_Z");
write_encoding (decl);
+ if (DECL_LANG_SPECIFIC (decl)
+ && (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
+ || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)))
+ /* We need a distinct mangled name for these entities, but
+ we should never actually output it. So, we append some
+ characters the assembler won't like. */
+ write_string (" *INTERNAL* ");
}
}
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree fn_type;
+ tree d;
if (decl_is_template_id (decl, NULL))
- fn_type = get_mostly_instantiated_function_type (decl);
+ {
+ save_partially_mangled_name ();
+ fn_type = get_mostly_instantiated_function_type (decl);
+ restore_partially_mangled_name ();
+ /* FN_TYPE will not have parameter types for in-charge or
+ VTT parameters. Therefore, we pass NULL_TREE to
+ write_bare_function_type -- otherwise, it will get
+ confused about which artificial parameters to skip. */
+ d = NULL_TREE;
+ }
else
- fn_type = TREE_TYPE (decl);
+ {
+ fn_type = TREE_TYPE (decl);
+ d = decl;
+ }
write_bare_function_type (fn_type,
(!DECL_CONSTRUCTOR_P (decl)
&& !DECL_DESTRUCTOR_P (decl)
&& !DECL_CONV_FN_P (decl)
&& decl_is_template_id (decl, NULL)),
- decl);
+ d);
}
}
write_string ("St");
write_unqualified_name (decl);
}
- /* If not, it should be either in the global namespace, or directly
- in a local function scope. */
- else if (context == global_namespace
- || context == NULL
- || TREE_CODE (context) == FUNCTION_DECL)
- write_unqualified_name (decl);
- else
- abort ();
+ else
+ {
+ /* If not, it should be either in the global namespace, or directly
+ in a local function scope. */
+ gcc_assert (context == global_namespace
+ || context == NULL
+ || TREE_CODE (context) == FUNCTION_DECL);
+
+ write_unqualified_name (decl);
+ }
}
/* <unscoped-template-name> ::= <unscoped-name>
/* Find the template decl. */
if (decl_is_template_id (decl, &template_info))
template = TI_TEMPLATE (template_info);
- else if (CLASSTYPE_TEMPLATE_ID_P (type))
- template = TYPE_TI_TEMPLATE (type);
else
- /* Oops, not a template. */
- abort ();
+ {
+ gcc_assert (CLASSTYPE_TEMPLATE_ID_P (type));
+
+ template = TYPE_TI_TEMPLATE (type);
+ }
/* For a member template, though, the template name for the
innermost name must have all the outer template levels
write_special_name_constructor (decl);
else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
write_special_name_destructor (decl);
+ else if (DECL_NAME (decl) == NULL_TREE)
+ write_source_name (DECL_ASSEMBLER_NAME (decl));
else if (DECL_CONV_FN_P (decl))
{
/* Conversion operator. Handle it right here.
tree type;
if (decl_is_template_id (decl, NULL))
{
- tree fn_type = get_mostly_instantiated_function_type (decl);
+ tree fn_type;
+ save_partially_mangled_name ();
+ fn_type = get_mostly_instantiated_function_type (decl);
+ restore_partially_mangled_name ();
type = TREE_TYPE (fn_type);
}
else
write_type (type);
}
-/* Non-termial <source-name>. IDENTIFIER is an IDENTIFIER_NODE.
+/* Non-terminal <source-name>. IDENTIFIER is an IDENTIFIER_NODE.
<source-name> ::= </length/ number> <identifier> */
}
type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
- base = build_int_2 (chunk, 0);
- n = build_int_2 (TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
- TREE_TYPE (n) = TREE_TYPE (base) = type;
+ base = build_int_cstu (type, chunk);
+ n = build_int_cst_wide (type,
+ TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
if (sign < 0)
{
}
do
{
- tree d = fold (build (FLOOR_DIV_EXPR, type, n, base));
- tree tmp = fold (build (MULT_EXPR, type, d, base));
+ tree d = fold (build2 (FLOOR_DIV_EXPR, type, n, base));
+ tree tmp = fold (build2 (MULT_EXPR, type, d, base));
unsigned c;
done = integer_zerop (d);
- tmp = fold (build (MINUS_EXPR, type, n, tmp));
+ tmp = fold (build2 (MINUS_EXPR, type, n, tmp));
c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
- done ? 1 : chunk_digits);
+ done ? 1 : chunk_digits);
ptr -= c;
count += c;
n = d;
static void
write_special_name_constructor (const tree ctor)
{
- if (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
- /* Even though we don't ever emit a definition of the
- old-style destructor, we still have to consider entities
- (like static variables) nested inside it. */
- || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
- write_string ("C1");
- else if (DECL_BASE_CONSTRUCTOR_P (ctor))
+ if (DECL_BASE_CONSTRUCTOR_P (ctor))
write_string ("C2");
else
- abort ();
+ {
+ gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
+ /* Even though we don't ever emit a definition of
+ the old-style destructor, we still have to
+ consider entities (like static variables) nested
+ inside it. */
+ || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor));
+ write_string ("C1");
+ }
}
/* Handle destructor productions of non-terminal <special-name>.
{
if (DECL_DELETING_DESTRUCTOR_P (dtor))
write_string ("D0");
- else if (DECL_COMPLETE_DESTRUCTOR_P (dtor)
- /* Even though we don't ever emit a definition of the
- old-style destructor, we still have to consider entities
- (like static variables) nested inside it. */
- || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
- write_string ("D1");
else if (DECL_BASE_DESTRUCTOR_P (dtor))
write_string ("D2");
else
- abort ();
+ {
+ gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor)
+ /* Even though we don't ever emit a definition of
+ the old-style destructor, we still have to
+ consider entities (like static variables) nested
+ inside it. */
+ || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor));
+ write_string ("D1");
+ }
}
/* Return the discriminator for ENTITY appearing inside
}
/* Return the discriminator for STRING, a string literal used inside
- FUNCTION. The disciminator is the lexical ordinal of STRING among
+ FUNCTION. The discriminator is the lexical ordinal of STRING among
string literals used in FUNCTION. */
static int
case BOOLEAN_TYPE:
case INTEGER_TYPE: /* Includes wchar_t. */
case REAL_TYPE:
+ {
+ /* Handle any target-specific fundamental types. */
+ const char *target_mangling
+ = targetm.mangle_fundamental_type (type);
+
+ if (target_mangling)
+ {
+ write_string (target_mangling);
+ return;
+ }
+
/* If this is a typedef, TYPE may not be one of
the standard builtin type nodes, but an alias of one. Use
TYPE_MAIN_VARIANT to get to the underlying builtin type. */
write_builtin_type (TYPE_MAIN_VARIANT (type));
++is_builtin_type;
break;
+ }
case COMPLEX_TYPE:
write_char ('C');
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
if (itk == itk_none)
{
tree t = c_common_type_for_mode (TYPE_MODE (type),
- TREE_UNSIGNED (type));
+ TYPE_UNSIGNED (type));
if (type == t)
{
- if (TYPE_PRECISION (type) == 128)
- write_char (TREE_UNSIGNED (type) ? 'o' : 'n');
- else
- /* Couldn't find this type. */
- abort ();
+ gcc_assert (TYPE_PRECISION (type) == 128);
+ write_char (TYPE_UNSIGNED (type) ? 'o' : 'n');
}
else
{
else if (type == long_double_type_node)
write_char ('e');
else
- abort ();
+ gcc_unreachable ();
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
fixed-length. */
varargs_p = 0;
/* A void type better be the last one. */
- my_friendly_assert (TREE_CHAIN (parm_types) == NULL, 20000523);
+ gcc_assert (TREE_CHAIN (parm_types) == NULL);
}
else
write_type (parm);
static void
write_template_args (tree args)
{
+ int i;
+ int length = TREE_VEC_LENGTH (args);
+
MANGLE_TRACE_TREE ("template-args", args);
write_char ('I');
- if (TREE_CODE (args) == TREE_VEC)
- {
- int i;
- int length = TREE_VEC_LENGTH (args);
- my_friendly_assert (length > 0, 20000422);
+ gcc_assert (length > 0);
- if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
- {
- /* We have nested template args. We want the innermost template
- argument list. */
- args = TREE_VEC_ELT (args, length - 1);
- length = TREE_VEC_LENGTH (args);
- }
- for (i = 0; i < length; ++i)
- write_template_arg (TREE_VEC_ELT (args, i));
- }
- else
+ if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
{
- my_friendly_assert (TREE_CODE (args) == TREE_LIST, 20021014);
-
- while (args)
- {
- write_template_arg (TREE_VALUE (args));
- args = TREE_CHAIN (args);
- }
+ /* We have nested template args. We want the innermost template
+ argument list. */
+ args = TREE_VEC_ELT (args, length - 1);
+ length = TREE_VEC_LENGTH (args);
}
-
+ for (i = 0; i < length; ++i)
+ write_template_arg (TREE_VEC_ELT (args, i));
+
write_char ('E');
}
code = TREE_CODE (expr);
+ /* Skip NOP_EXPRs. They can occur when (say) a pointer argument
+ is converted (via qualification conversions) to another
+ type. */
+ while (TREE_CODE (expr) == NOP_EXPR
+ || TREE_CODE (expr) == NON_LVALUE_EXPR)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ code = TREE_CODE (expr);
+ }
+
/* Handle pointers-to-members by making them look like expression
nodes. */
if (code == PTRMEM_CST)
code = TREE_CODE (expr);
}
- /* Skip NOP_EXPRs. They can occur when (say) a pointer argument
- is converted (via qualification conversions) to another
- type. */
- while (TREE_CODE (expr) == NOP_EXPR
- || TREE_CODE (expr) == NON_LVALUE_EXPR)
- {
- expr = TREE_OPERAND (expr, 0);
- code = TREE_CODE (expr);
- }
-
/* Handle template parameters. */
if (code == TEMPLATE_TYPE_PARM
|| code == TEMPLATE_TEMPLATE_PARM
|| code == TEMPLATE_PARM_INDEX)
write_template_param (expr);
/* Handle literals. */
- else if (TREE_CODE_CLASS (code) == 'c'
+ else if (TREE_CODE_CLASS (code) == tcc_constant
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (expr);
else if (DECL_P (expr))
if (code == CONST_DECL)
G.need_abi_warning = 1;
write_char ('L');
- write_mangled_name (expr);
+ write_mangled_name (expr, false);
write_char ('E');
}
else if (TREE_CODE (expr) == SIZEOF_EXPR
case CAST_EXPR:
write_type (TREE_TYPE (expr));
- write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
+ /* There is no way to mangle a zero-operand cast like
+ "T()". */
+ if (!TREE_OPERAND (expr, 0))
+ sorry ("zero-operand casts cannot be mangled due to a defect "
+ "in the C++ ABI");
+ else
+ write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
break;
case STATIC_CAST_EXPR:
template_id = TREE_OPERAND (expr, 1);
name = TREE_OPERAND (template_id, 0);
/* FIXME: What about operators? */
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
- 20030707);
+ gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
write_source_name (TREE_OPERAND (template_id, 0));
write_template_args (TREE_OPERAND (template_id, 1));
}
default:
for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
- write_expression (TREE_OPERAND (expr, i));
+ {
+ tree operand = TREE_OPERAND (expr, i);
+ /* As a GNU expression, the middle operand of a
+ conditional may be omitted. Since expression
+ manglings are supposed to represent the input token
+ stream, there's no good way to mangle such an
+ expression without extending the C++ ABI. */
+ if (code == COND_EXPR && i == 1 && !operand)
+ {
+ error ("omitted middle operand to %<?:%> operand "
+ "cannot be mangled");
+ continue;
+ }
+ write_expression (operand);
+ }
}
}
}
static void
write_template_arg_literal (const tree value)
{
- tree type = TREE_TYPE (value);
write_char ('L');
- write_type (type);
+ write_type (TREE_TYPE (value));
- if (TREE_CODE (value) == CONST_DECL)
- write_integer_cst (DECL_INITIAL (value));
- else if (TREE_CODE (value) == INTEGER_CST)
+ switch (TREE_CODE (value))
{
- if (same_type_p (type, boolean_type_node))
- {
- if (value == boolean_false_node || integer_zerop (value))
- write_unsigned_number (0);
- else if (value == boolean_true_node)
- write_unsigned_number (1);
- else
- abort ();
- }
- else
- write_integer_cst (value);
- }
- else if (TREE_CODE (value) == REAL_CST)
- write_real_cst (value);
- else
- abort ();
+ case CONST_DECL:
+ write_integer_cst (DECL_INITIAL (value));
+ break;
+
+ case INTEGER_CST:
+ gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
+ || integer_zerop (value) || integer_onep (value));
+ write_integer_cst (value);
+ break;
+ case REAL_CST:
+ write_real_cst (value);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
write_char ('E');
}
-/* Non-terminal <tempalate-arg>.
+/* Non-terminal <template-arg>.
<template-arg> ::= <type> # type
::= L <type> </value/ number> E # literal
MANGLE_TRACE_TREE ("template-arg", node);
- /* A template template paramter's argument list contains TREE_LIST
+ /* A template template parameter's argument list contains TREE_LIST
nodes of which the value field is the the actual argument. */
if (code == TREE_LIST)
{
code = TREE_CODE (node);
}
}
+
+ if (TREE_CODE (node) == NOP_EXPR
+ && TREE_CODE (TREE_TYPE (node)) == REFERENCE_TYPE)
+ {
+ /* Template parameters can be of reference type. To maintain
+ internal consistency, such arguments use a conversion from
+ address of object to reference type. */
+ gcc_assert (TREE_CODE (TREE_OPERAND (node, 0)) == ADDR_EXPR);
+ if (abi_version_at_least (2))
+ node = TREE_OPERAND (TREE_OPERAND (node, 0), 0);
+ else
+ G.need_abi_warning = 1;
+ }
if (TYPE_P (node))
write_type (node);
else if (code == TEMPLATE_DECL)
/* A template appearing as a template arg is a template template arg. */
write_template_template_arg (node);
- else if ((TREE_CODE_CLASS (code) == 'c' && code != PTRMEM_CST)
+ else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (node);
else if (DECL_P (node))
{
- /* G++ 3.2 incorrectly mangled non-type template arguments of
- enumeration type using their names. */
- if (code == CONST_DECL)
+ /* Until ABI version 2, non-type template arguments of
+ enumeration type were mangled using their names. */
+ if (code == CONST_DECL && !abi_version_at_least (2))
G.need_abi_warning = 1;
write_char ('L');
- write_char ('Z');
+ /* Until ABI version 3, the underscore before the mangled name
+ was incorrectly omitted. */
+ if (!abi_version_at_least (3))
+ {
+ G.need_abi_warning = 1;
+ write_char ('Z');
+ }
+ else
+ write_string ("_Z");
write_encoding (node);
write_char ('E');
}
write_unsigned_number (tree_low_cst (max, 1));
}
else
- write_expression (TREE_OPERAND (max, 0));
+ {
+ max = TREE_OPERAND (max, 0);
+ if (!abi_version_at_least (2))
+ {
+ /* value_dependent_expression_p presumes nothing is
+ dependent when PROCESSING_TEMPLATE_DECL is zero. */
+ ++processing_template_decl;
+ if (!value_dependent_expression_p (max))
+ G.need_abi_warning = 1;
+ --processing_template_decl;
+ }
+ write_expression (max);
+ }
+
}
write_char ('_');
write_type (TREE_TYPE (type));
break;
default:
- abort ();
+ gcc_unreachable ();
}
write_char ('T');
/* Start mangling ENTITY. */
static inline void
-start_mangling (const tree entity)
+start_mangling (const tree entity, const bool ident_p)
{
G.entity = entity;
G.need_abi_warning = false;
- VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
- obstack_free (&G.name_obstack, obstack_base (&G.name_obstack));
+ if (!ident_p)
+ {
+ obstack_free (&name_obstack, name_base);
+ mangle_obstack = &name_obstack;
+ name_base = obstack_alloc (&name_obstack, 0);
+ }
+ else
+ mangle_obstack = &ident_hash->stack;
}
/* Done with mangling. Return the generated mangled name. If WARN is
finish_mangling (const bool warn)
{
if (warn_abi && warn && G.need_abi_warning)
- warning ("the mangled name of `%D' will change in a future "
+ warning ("the mangled name of %qD will change in a future "
"version of GCC",
G.entity);
/* Clear all the substitutions. */
- G.substitutions = 0;
+ VARRAY_CLEAR (G.substitutions);
/* Null-terminate the string. */
write_char ('\0');
- return (const char *) obstack_base (&G.name_obstack);
+ return (const char *) obstack_finish (mangle_obstack);
}
/* Initialize data structures for mangling. */
void
init_mangle (void)
{
- gcc_obstack_init (&G.name_obstack);
+ gcc_obstack_init (&name_obstack);
+ name_base = obstack_alloc (&name_obstack, 0);
+ VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
/* Cache these identifiers for quick comparison when checking for
standard substitutions. */
{
const char *result;
- start_mangling (decl);
+ start_mangling (decl, /*ident_p=*/true);
if (TREE_CODE (decl) == TYPE_DECL)
write_type (TREE_TYPE (decl));
- else if (/* The names of `extern "C"' functions are not mangled. */
- (DECL_EXTERN_C_FUNCTION_P (decl)
- /* But overloaded operator names *are* mangled. */
- && !DECL_OVERLOADED_OPERATOR_P (decl))
- /* The names of global variables aren't mangled either. */
- || (TREE_CODE (decl) == VAR_DECL
- && CP_DECL_CONTEXT (decl) == global_namespace)
- /* And neither are `extern "C"' variables. */
- || (TREE_CODE (decl) == VAR_DECL
- && DECL_EXTERN_C_P (decl)))
- write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
else
- {
- write_mangled_name (decl);
- if (DECL_LANG_SPECIFIC (decl)
- && (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
- || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)))
- /* We need a distinct mangled name for these entities, but
- we should never actually output it. So, we append some
- characters the assembler won't like. */
- write_string (" *INTERNAL* ");
- }
-
+ write_mangled_name (decl, true);
+
result = finish_mangling (/*warn=*/true);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
return result;
}
+/* Like get_identifier, except that NAME is assumed to have been
+ allocated on the obstack used by the identifier hash table. */
+
+static inline tree
+get_identifier_nocopy (const char *name)
+{
+ hashnode ht_node = ht_lookup (ident_hash, (const unsigned char *) name,
+ strlen (name), HT_ALLOCED);
+ return HT_IDENT_TO_GCC_IDENT (ht_node);
+}
+
/* Create an identifier for the external mangled name of DECL. */
void
mangle_decl (const tree decl)
{
- tree id = get_identifier (mangle_decl_string (decl));
-
- SET_DECL_ASSEMBLER_NAME (decl, id);
+ SET_DECL_ASSEMBLER_NAME (decl,
+ get_identifier_nocopy (mangle_decl_string (decl)));
}
/* Generate the mangled representation of TYPE. */
{
const char *result;
- start_mangling (type);
+ start_mangling (type, /*ident_p=*/false);
write_type (type);
result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
return result;
}
-/* Create an identifier for the mangled representation of TYPE. */
-
-tree
-mangle_type (const tree type)
-{
- return get_identifier (mangle_type_string (type));
-}
-
/* Create an identifier for the mangled name of a special component
for belonging to TYPE. CODE is the ABI-specified code for this
component. */
/* We don't have an actual decl here for the special component, so
we can't just process the <encoded-name>. Instead, fake it. */
- start_mangling (type);
+ start_mangling (type, /*ident_p=*/true);
/* Start the mangling. */
write_string ("_Z");
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
- return get_identifier (result);
+ return get_identifier_nocopy (result);
}
/* Create an identifier for the mangled representation of the typeinfo
{
const char *result;
- start_mangling (type);
+ start_mangling (type, /*ident_p=*/true);
write_string ("_Z");
write_string ("TC");
result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
- return get_identifier (result);
+ return get_identifier_nocopy (result);
}
/* Mangle a this pointer or result pointer adjustment.
{
const char *result;
- start_mangling (fn_decl);
+ start_mangling (fn_decl, /*ident_p=*/true);
write_string ("_Z");
write_char ('T');
result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", result);
- return get_identifier (result);
+ return get_identifier_nocopy (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. */
+ operator to TYPE. The nodes are IDENTIFIERs whose TREE_TYPE is the
+ TYPE. */
static GTY ((param_is (union tree_node))) htab_t conv_type_names;
static hashval_t
hash_type (const void *val)
{
- return htab_hash_pointer (TREE_PURPOSE ((tree) val));
+ return (hashval_t) TYPE_UID (TREE_TYPE ((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 TREE_TYPE ((tree) val1) == (tree) val2;
}
/* Return an identifier for the mangled unqualified name for a
{
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 %lu",
- (unsigned long) htab_elements (conv_type_names));
- identifier = get_identifier (buffer);
- *slot = build_tree_list (type, identifier);
+ (hashval_t) TYPE_UID (type), INSERT);
+ identifier = (tree)*slot;
+ if (!identifier)
+ {
+ char buffer[64];
+
+ /* Create a unique name corresponding to TYPE. */
+ sprintf (buffer, "operator %lu",
+ (unsigned long) htab_elements (conv_type_names));
+ identifier = get_identifier (buffer);
+ *slot = identifier;
+
+ /* Hang TYPE off the identifier so it can be found easily later
+ when performing conversions. */
+ TREE_TYPE (identifier) = type;
+
+ /* Set bits on the identifier so we know later it's a conversion. */
+ IDENTIFIER_OPNAME_P (identifier) = 1;
+ IDENTIFIER_TYPENAME_P (identifier) = 1;
+ }
- /* 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
- performing conversions. */
- TREE_TYPE (identifier) = type;
-
return identifier;
}
tree
mangle_guard_variable (const tree variable)
{
- start_mangling (variable);
+ start_mangling (variable, /*ident_p=*/true);
write_string ("_ZGV");
if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
/* The name of a guard variable for a reference temporary should refer
write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
else
write_name (variable, /*ignore_local_scope=*/0);
- return get_identifier (finish_mangling (/*warn=*/false));
+ return get_identifier_nocopy (finish_mangling (/*warn=*/false));
}
/* Return an identifier for the name of a temporary variable used to
tree
mangle_ref_init_variable (const tree variable)
{
- start_mangling (variable);
+ start_mangling (variable, /*ident_p=*/true);
write_string ("_ZGR");
write_name (variable, /*ignore_local_scope=*/0);
- return get_identifier (finish_mangling (/*warn=*/false));
+ return get_identifier_nocopy (finish_mangling (/*warn=*/false));
}
\f
else if (type == java_boolean_type_node)
write_char ('b');
else
- abort ();
+ gcc_unreachable ();
}
#include "gt-cp-mangle.h"