aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/cp/mangle.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cp/mangle.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/cp/mangle.c2957
1 files changed, 2957 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/cp/mangle.c b/gcc-4.2.1-5666.3/gcc/cp/mangle.c
new file mode 100644
index 000000000..77f9b9977
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/cp/mangle.c
@@ -0,0 +1,2957 @@
+/* Name mangling for the 3.0 C++ ABI.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+ Written by Alex Samuel <samuel@codesourcery.com>
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* This file implements mangling of C++ names according to the IA64
+ C++ ABI specification. A mangled name encodes a function or
+ variable's name, scope, type, and/or template arguments into a text
+ identifier. This identifier is used as the function's or
+ variable's linkage name, to preserve compatibility between C++'s
+ language features (templates, scoping, and overloading) and C
+ linkers.
+
+ Additionally, g++ uses mangled names internally. To support this,
+ mangling of types is allowed, even though the mangled name of a
+ type should not appear by itself as an exported name. Ditto for
+ uninstantiated templates.
+
+ The primary entry point for this module is mangle_decl, which
+ returns an identifier containing the mangled name for a decl.
+ Additional entry points are provided to build mangled names of
+ particular constructs when the appropriate decl for that construct
+ is not available. These are:
+
+ mangle_typeinfo_for_type: typeinfo data
+ mangle_typeinfo_string_for_type: typeinfo type name
+ mangle_vtbl_for_type: virtual table data
+ mangle_vtt_for_type: VTT data
+ mangle_ctor_vtbl_for_type: `C-in-B' constructor virtual table data
+ mangle_thunk: thunk function or entry */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "cp-tree.h"
+#include "real.h"
+#include "obstack.h"
+#include "toplev.h"
+#include "varray.h"
+#include "flags.h"
+#include "target.h"
+
+/* Debugging support. */
+
+/* Define DEBUG_MANGLE to enable very verbose trace messages. */
+#ifndef DEBUG_MANGLE
+#define DEBUG_MANGLE 0
+#endif
+
+/* Macros for tracing the write_* functions. */
+#if DEBUG_MANGLE
+# define MANGLE_TRACE(FN, INPUT) \
+ fprintf (stderr, " %-24s: %-24s\n", (FN), (INPUT))
+# define MANGLE_TRACE_TREE(FN, NODE) \
+ fprintf (stderr, " %-24s: %-24s (%p)\n", \
+ (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
+#else
+# define MANGLE_TRACE(FN, INPUT)
+# define MANGLE_TRACE_TREE(FN, NODE)
+#endif
+
+/* Nonzero if NODE is a class template-id. We can't rely on
+ CLASSTYPE_USE_TEMPLATE here because of tricky bugs in the parser
+ that hard to distinguish A<T> from A, where A<T> is the type as
+ instantiated outside of the template, and A is the type used
+ without parameters inside the template. */
+#define CLASSTYPE_TEMPLATE_ID_P(NODE) \
+ (TYPE_LANG_SPECIFIC (NODE) != NULL \
+ && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM \
+ || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL \
+ && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
+
+/* Things we only need one of. This module is not reentrant. */
+typedef struct globals GTY(())
+{
+ /* An array of the current substitution candidates, in the order
+ we've seen them. */
+ VEC(tree,gc) *substitutions;
+
+ /* The entity that is being mangled. */
+ tree GTY ((skip)) entity;
+
+ /* True if the mangling will be different in a future version of the
+ ABI. */
+ bool need_abi_warning;
+} 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. */
+typedef enum
+{
+ SUBID_ALLOCATOR,
+ SUBID_BASIC_STRING,
+ SUBID_CHAR_TRAITS,
+ SUBID_BASIC_ISTREAM,
+ SUBID_BASIC_OSTREAM,
+ SUBID_BASIC_IOSTREAM,
+ SUBID_MAX
+}
+substitution_identifier_index_t;
+
+/* For quick substitution checks, look up these common identifiers
+ once only. */
+static GTY(()) tree subst_identifiers[SUBID_MAX];
+
+/* Single-letter codes for builtin integer types, defined in
+ <builtin-type>. These are indexed by integer_type_kind values. */
+static const char
+integer_type_codes[itk_none] =
+{
+ 'c', /* itk_char */
+ 'a', /* itk_signed_char */
+ 'h', /* itk_unsigned_char */
+ 's', /* itk_short */
+ 't', /* itk_unsigned_short */
+ 'i', /* itk_int */
+ 'j', /* itk_unsigned_int */
+ 'l', /* itk_long */
+ 'm', /* itk_unsigned_long */
+ 'x', /* itk_long_long */
+ 'y' /* itk_unsigned_long_long */
+};
+
+static int decl_is_template_id (const tree, tree* const);
+
+/* Functions for handling substitutions. */
+
+static inline tree canonicalize_for_substitution (tree);
+static void add_substitution (tree);
+static inline int is_std_substitution (const tree,
+ const substitution_identifier_index_t);
+static inline int is_std_substitution_char (const tree,
+ const substitution_identifier_index_t);
+static int find_substitution (tree);
+static void mangle_call_offset (const tree, const tree);
+
+/* Functions for emitting mangled representations of things. */
+
+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);
+static void write_unscoped_template_name (const tree);
+static void write_nested_name (const tree);
+static void write_prefix (const tree);
+static void write_template_prefix (const tree);
+static void write_unqualified_name (const tree);
+static void write_conversion_operator_name (const tree);
+static void write_source_name (tree);
+static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
+ const unsigned int);
+static void write_number (unsigned HOST_WIDE_INT, const int,
+ const unsigned int);
+static void write_integer_cst (const tree);
+static void write_real_cst (const tree);
+static void write_identifier (const char *);
+static void write_special_name_constructor (const tree);
+static void write_special_name_destructor (const tree);
+static void write_type (tree);
+static int write_CV_qualifiers_for_type (const tree);
+static void write_builtin_type (tree);
+static void write_function_type (const tree);
+static void write_bare_function_type (const tree, const int, const tree);
+static void write_method_parms (tree, const int, const tree);
+static void write_class_enum_type (const tree);
+static void write_template_args (tree);
+static void write_expression (tree);
+static void write_template_arg_literal (const tree);
+static void write_template_arg (tree);
+static void write_template_template_arg (const tree);
+static void write_array_type (const tree);
+static void write_pointer_to_member_type (const tree);
+static void write_template_param (const tree);
+static void write_template_template_param (const tree);
+static void write_substitution (const int);
+static int discriminator_for_local_entity (tree);
+static int discriminator_for_string_literal (tree, tree);
+static void write_discriminator (const int);
+static void write_local_name (const tree, const tree, const tree);
+static void dump_substitution_candidates (void);
+static const char *mangle_decl_string (const tree);
+
+/* Control functions. */
+
+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 *);
+
+/* Foreign language functions. */
+
+static void write_java_integer_type_codes (const tree);
+
+/* Append a single character to the end of the mangled
+ representation. */
+#define write_char(CHAR) \
+ obstack_1grow (mangle_obstack, (CHAR))
+
+/* Append a sized buffer to the end of the mangled representation. */
+#define write_chars(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 (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
+ decl). See write_template_prefix for more information on what this
+ is used for. */
+#define NESTED_TEMPLATE_MATCH(NODE1, NODE2) \
+ (TREE_CODE (NODE1) == TREE_LIST \
+ && TREE_CODE (NODE2) == TREE_LIST \
+ && ((TYPE_P (TREE_PURPOSE (NODE1)) \
+ && same_type_p (TREE_PURPOSE (NODE1), TREE_PURPOSE (NODE2))) \
+ || TREE_PURPOSE (NODE1) == TREE_PURPOSE (NODE2)) \
+ && TREE_VALUE (NODE1) == TREE_VALUE (NODE2))
+
+/* Write out an unsigned quantity in base 10. */
+#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 = XNEWVEC (char, 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. */
+
+static int
+decl_is_template_id (const tree decl, tree* const template_info)
+{
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ /* TYPE_DECLs are handled specially. Look at its type to decide
+ if this is a template instantiation. */
+ const tree type = TREE_TYPE (decl);
+
+ if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_ID_P (type))
+ {
+ if (template_info != NULL)
+ /* For a templated TYPE_DECL, the template info is hanging
+ off the type. */
+ *template_info = TYPE_TEMPLATE_INFO (type);
+ return 1;
+ }
+ }
+ else
+ {
+ /* Check if this is a primary template. */
+ if (DECL_LANG_SPECIFIC (decl) != NULL
+ && DECL_USE_TEMPLATE (decl)
+ && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))
+ && TREE_CODE (decl) != TEMPLATE_DECL)
+ {
+ if (template_info != NULL)
+ /* For most templated decls, the template info is hanging
+ off the decl. */
+ *template_info = DECL_TEMPLATE_INFO (decl);
+ return 1;
+ }
+ }
+
+ /* It's not a template id. */
+ return 0;
+}
+
+/* Produce debugging output of current substitution candidates. */
+
+static void
+dump_substitution_candidates (void)
+{
+ unsigned i;
+ tree el;
+
+ fprintf (stderr, " ++ substitutions ");
+ for (i = 0; VEC_iterate (tree, G.substitutions, i, el); ++i)
+ {
+ const char *name = "???";
+
+ if (i > 0)
+ fprintf (stderr, " ");
+ if (DECL_P (el))
+ name = IDENTIFIER_POINTER (DECL_NAME (el));
+ else if (TREE_CODE (el) == TREE_LIST)
+ name = IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (el)));
+ else if (TYPE_NAME (el))
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (el)));
+ fprintf (stderr, " S%d_ = ", i - 1);
+ if (TYPE_P (el) &&
+ (CP_TYPE_RESTRICT_P (el)
+ || CP_TYPE_VOLATILE_P (el)
+ || CP_TYPE_CONST_P (el)))
+ fprintf (stderr, "CV-");
+ fprintf (stderr, "%s (%s at %p)\n",
+ name, tree_code_name[TREE_CODE (el)], (void *) el);
+ }
+}
+
+/* Both decls and types can be substitution candidates, but sometimes
+ they refer to the same thing. For instance, a TYPE_DECL and
+ RECORD_TYPE for the same class refer to the same thing, and should
+ be treated accordingly in substitutions. This function returns a
+ canonicalized tree node representing NODE that is used when adding
+ and substitution candidates and finding matches. */
+
+static inline tree
+canonicalize_for_substitution (tree node)
+{
+ /* For a TYPE_DECL, use the type instead. */
+ if (TREE_CODE (node) == TYPE_DECL)
+ node = TREE_TYPE (node);
+ if (TYPE_P (node))
+ node = canonical_type_variant (node);
+
+ return node;
+}
+
+/* Add NODE as a substitution candidate. NODE must not already be on
+ the list of candidates. */
+
+static void
+add_substitution (tree node)
+{
+ tree c;
+
+ if (DEBUG_MANGLE)
+ fprintf (stderr, " ++ add_substitution (%s at %10p)\n",
+ tree_code_name[TREE_CODE (node)], (void *) node);
+
+ /* Get the canonicalized substitution candidate for NODE. */
+ c = canonicalize_for_substitution (node);
+ if (DEBUG_MANGLE && c != node)
+ fprintf (stderr, " ++ using candidate (%s at %10p)\n",
+ tree_code_name[TREE_CODE (node)], (void *) node);
+ node = c;
+
+#if ENABLE_CHECKING
+ /* Make sure NODE isn't already a candidate. */
+ {
+ int i;
+ tree candidate;
+
+ for (i = 0; VEC_iterate (tree, G.substitutions, i, candidate); i++)
+ {
+ gcc_assert (!(DECL_P (node) && node == candidate));
+ gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
+ && same_type_p (node, candidate)));
+ }
+ }
+#endif /* ENABLE_CHECKING */
+
+ /* Put the decl onto the varray of substitution candidates. */
+ VEC_safe_push (tree, gc, G.substitutions, node);
+
+ if (DEBUG_MANGLE)
+ dump_substitution_candidates ();
+}
+
+/* Helper function for find_substitution. Returns nonzero if NODE,
+ which may be a decl or a CLASS_TYPE, is a template-id with template
+ name of substitution_index[INDEX] in the ::std namespace. */
+
+static inline int
+is_std_substitution (const tree node,
+ const substitution_identifier_index_t index)
+{
+ tree type = NULL;
+ tree decl = NULL;
+
+ if (DECL_P (node))
+ {
+ type = TREE_TYPE (node);
+ decl = node;
+ }
+ else if (CLASS_TYPE_P (node))
+ {
+ type = node;
+ decl = TYPE_NAME (node);
+ }
+ else
+ /* These are not the droids you're looking for. */
+ return 0;
+
+ return (DECL_NAMESPACE_STD_P (CP_DECL_CONTEXT (decl))
+ && TYPE_LANG_SPECIFIC (type)
+ && TYPE_TEMPLATE_INFO (type)
+ && (DECL_NAME (TYPE_TI_TEMPLATE (type))
+ == subst_identifiers[index]));
+}
+
+/* Helper function for find_substitution. Returns nonzero if NODE,
+ which may be a decl or a CLASS_TYPE, is the template-id
+ ::std::identifier<char>, where identifier is
+ substitution_index[INDEX]. */
+
+static inline int
+is_std_substitution_char (const tree node,
+ const substitution_identifier_index_t index)
+{
+ tree args;
+ /* Check NODE's name is ::std::identifier. */
+ if (!is_std_substitution (node, index))
+ return 0;
+ /* Figure out its template args. */
+ if (DECL_P (node))
+ args = DECL_TI_ARGS (node);
+ else if (CLASS_TYPE_P (node))
+ args = CLASSTYPE_TI_ARGS (node);
+ else
+ /* Oops, not a template. */
+ return 0;
+ /* NODE's template arg list should be <char>. */
+ return
+ TREE_VEC_LENGTH (args) == 1
+ && TREE_VEC_ELT (args, 0) == char_type_node;
+}
+
+/* Check whether a substitution should be used to represent NODE in
+ the mangling.
+
+ First, check standard special-case substitutions.
+
+ <substitution> ::= St
+ # ::std
+
+ ::= Sa
+ # ::std::allocator
+
+ ::= Sb
+ # ::std::basic_string
+
+ ::= Ss
+ # ::std::basic_string<char,
+ ::std::char_traits<char>,
+ ::std::allocator<char> >
+
+ ::= Si
+ # ::std::basic_istream<char, ::std::char_traits<char> >
+
+ ::= So
+ # ::std::basic_ostream<char, ::std::char_traits<char> >
+
+ ::= Sd
+ # ::std::basic_iostream<char, ::std::char_traits<char> >
+
+ Then examine the stack of currently available substitution
+ candidates for entities appearing earlier in the same mangling
+
+ If a substitution is found, write its mangled representation and
+ return nonzero. If none is found, just return zero. */
+
+static int
+find_substitution (tree node)
+{
+ int i;
+ const int size = VEC_length (tree, G.substitutions);
+ tree decl;
+ tree type;
+
+ if (DEBUG_MANGLE)
+ fprintf (stderr, " ++ find_substitution (%s at %p)\n",
+ tree_code_name[TREE_CODE (node)], (void *) node);
+
+ /* Obtain the canonicalized substitution representation for NODE.
+ This is what we'll compare against. */
+ node = canonicalize_for_substitution (node);
+
+ /* Check for builtin substitutions. */
+
+ decl = TYPE_P (node) ? TYPE_NAME (node) : node;
+ type = TYPE_P (node) ? node : TREE_TYPE (node);
+
+ /* Check for std::allocator. */
+ if (decl
+ && is_std_substitution (decl, SUBID_ALLOCATOR)
+ && !CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)))
+ {
+ write_string ("Sa");
+ return 1;
+ }
+
+ /* Check for std::basic_string. */
+ if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
+ {
+ if (TYPE_P (node))
+ {
+ /* If this is a type (i.e. a fully-qualified template-id),
+ check for
+ std::basic_string <char,
+ std::char_traits<char>,
+ std::allocator<char> > . */
+ if (cp_type_quals (type) == TYPE_UNQUALIFIED
+ && CLASSTYPE_USE_TEMPLATE (type))
+ {
+ tree args = CLASSTYPE_TI_ARGS (type);
+ if (TREE_VEC_LENGTH (args) == 3
+ && same_type_p (TREE_VEC_ELT (args, 0), char_type_node)
+ && is_std_substitution_char (TREE_VEC_ELT (args, 1),
+ SUBID_CHAR_TRAITS)
+ && is_std_substitution_char (TREE_VEC_ELT (args, 2),
+ SUBID_ALLOCATOR))
+ {
+ write_string ("Ss");
+ return 1;
+ }
+ }
+ }
+ else
+ /* Substitute for the template name only if this isn't a type. */
+ {
+ write_string ("Sb");
+ return 1;
+ }
+ }
+
+ /* Check for basic_{i,o,io}stream. */
+ if (TYPE_P (node)
+ && cp_type_quals (type) == TYPE_UNQUALIFIED
+ && CLASS_TYPE_P (type)
+ && CLASSTYPE_USE_TEMPLATE (type)
+ && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
+ {
+ /* First, check for the template
+ args <char, std::char_traits<char> > . */
+ tree args = CLASSTYPE_TI_ARGS (type);
+ if (TREE_VEC_LENGTH (args) == 2
+ && TYPE_P (TREE_VEC_ELT (args, 0))
+ && same_type_p (TREE_VEC_ELT (args, 0), char_type_node)
+ && is_std_substitution_char (TREE_VEC_ELT (args, 1),
+ SUBID_CHAR_TRAITS))
+ {
+ /* Got them. Is this basic_istream? */
+ if (is_std_substitution (decl, SUBID_BASIC_ISTREAM))
+ {
+ write_string ("Si");
+ return 1;
+ }
+ /* Or basic_ostream? */
+ else if (is_std_substitution (decl, SUBID_BASIC_OSTREAM))
+ {
+ write_string ("So");
+ return 1;
+ }
+ /* Or basic_iostream? */
+ else if (is_std_substitution (decl, SUBID_BASIC_IOSTREAM))
+ {
+ write_string ("Sd");
+ return 1;
+ }
+ }
+ }
+
+ /* Check for namespace std. */
+ if (decl && DECL_NAMESPACE_STD_P (decl))
+ {
+ write_string ("St");
+ return 1;
+ }
+
+ /* Now check the list of available substitutions for this mangling
+ operation. */
+ for (i = 0; i < size; ++i)
+ {
+ tree candidate = VEC_index (tree, G.substitutions, i);
+ /* NODE is a matched to a candidate if it's the same decl node or
+ if it's the same type. */
+ if (decl == candidate
+ || (TYPE_P (candidate) && type && TYPE_P (type)
+ && same_type_p (type, candidate))
+ || NESTED_TEMPLATE_MATCH (node, candidate))
+ {
+ write_substitution (i);
+ return 1;
+ }
+ }
+
+ /* No substitution found. */
+ return 0;
+}
+
+
+/* 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 void
+write_mangled_name (const tree decl, bool top_level)
+{
+ MANGLE_TRACE_TREE ("mangled-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
+/* APPLE LOCAL begin mainline 2007-05-09 5173149 */ \
+ /* The names of non-static global variables aren't mangled. */
+ && DECL_EXTERNAL_LINKAGE_P (decl)
+/* APPLE LOCAL end mainline 2007-05-09 5173149 */ \
+ && (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
+ {
+ 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* ");
+ }
+}
+
+/* <encoding> ::= <function name> <bare-function-type>
+ ::= <data name> */
+
+static void
+write_encoding (const tree decl)
+{
+ MANGLE_TRACE_TREE ("encoding", decl);
+
+ if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl))
+ {
+ /* For overloaded operators write just the mangled name
+ without arguments. */
+ if (DECL_OVERLOADED_OPERATOR_P (decl))
+ write_name (decl, /*ignore_local_scope=*/0);
+ else
+ write_source_name (DECL_NAME (decl));
+ return;
+ }
+
+ write_name (decl, /*ignore_local_scope=*/0);
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ tree fn_type;
+ tree d;
+
+ if (decl_is_template_id (decl, NULL))
+ {
+ 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);
+ 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)),
+ d);
+ }
+}
+
+/* <name> ::= <unscoped-name>
+ ::= <unscoped-template-name> <template-args>
+ ::= <nested-name>
+ ::= <local-name>
+
+ If IGNORE_LOCAL_SCOPE is nonzero, this production of <name> is
+ called from <local-name>, which mangles the enclosing scope
+ elsewhere and then uses this function to mangle just the part
+ underneath the function scope. So don't use the <local-name>
+ production, to avoid an infinite recursion. */
+
+static void
+write_name (tree decl, const int ignore_local_scope)
+{
+ tree context;
+
+ MANGLE_TRACE_TREE ("name", decl);
+
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ /* In case this is a typedef, fish out the corresponding
+ TYPE_DECL for the main variant. */
+ decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+ context = TYPE_CONTEXT (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+ }
+ else
+ context = (DECL_CONTEXT (decl) == NULL) ? NULL : CP_DECL_CONTEXT (decl);
+
+ /* A decl in :: or ::std scope is treated specially. The former is
+ mangled using <unscoped-name> or <unscoped-template-name>, the
+ latter with a special substitution. Also, a name that is
+ directly in a local function scope is also mangled with
+ <unscoped-name> rather than a full <nested-name>. */
+ if (context == NULL
+ || context == global_namespace
+ || DECL_NAMESPACE_STD_P (context)
+ || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL))
+ {
+ tree template_info;
+ /* Is this a template instance? */
+ if (decl_is_template_id (decl, &template_info))
+ {
+ /* Yes: use <unscoped-template-name>. */
+ write_unscoped_template_name (TI_TEMPLATE (template_info));
+ write_template_args (TI_ARGS (template_info));
+ }
+ else
+ /* Everything else gets an <unqualified-name>. */
+ write_unscoped_name (decl);
+ }
+ else
+ {
+ /* Handle local names, unless we asked not to (that is, invoked
+ under <local-name>, to handle only the part of the name under
+ the local scope). */
+ if (!ignore_local_scope)
+ {
+ /* Scan up the list of scope context, looking for a
+ function. If we find one, this entity is in local
+ function scope. local_entity tracks context one scope
+ level down, so it will contain the element that's
+ directly in that function's scope, either decl or one of
+ its enclosing scopes. */
+ tree local_entity = decl;
+ while (context != NULL && context != global_namespace)
+ {
+ /* Make sure we're always dealing with decls. */
+ if (context != NULL && TYPE_P (context))
+ context = TYPE_NAME (context);
+ /* Is this a function? */
+ if (TREE_CODE (context) == FUNCTION_DECL)
+ {
+ /* Yes, we have local scope. Use the <local-name>
+ production for the innermost function scope. */
+ write_local_name (context, local_entity, decl);
+ return;
+ }
+ /* Up one scope level. */
+ local_entity = context;
+ context = CP_DECL_CONTEXT (context);
+ }
+
+ /* No local scope found? Fall through to <nested-name>. */
+ }
+
+ /* Other decls get a <nested-name> to encode their scope. */
+ write_nested_name (decl);
+ }
+}
+
+/* <unscoped-name> ::= <unqualified-name>
+ ::= St <unqualified-name> # ::std:: */
+
+static void
+write_unscoped_name (const tree decl)
+{
+ tree context = CP_DECL_CONTEXT (decl);
+
+ MANGLE_TRACE_TREE ("unscoped-name", decl);
+
+ /* Is DECL in ::std? */
+ if (DECL_NAMESPACE_STD_P (context))
+ {
+ write_string ("St");
+ write_unqualified_name (decl);
+ }
+ 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>
+ ::= <substitution> */
+
+static void
+write_unscoped_template_name (const tree decl)
+{
+ MANGLE_TRACE_TREE ("unscoped-template-name", decl);
+
+ if (find_substitution (decl))
+ return;
+ write_unscoped_name (decl);
+ add_substitution (decl);
+}
+
+/* Write the nested name, including CV-qualifiers, of DECL.
+
+ <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+
+ <CV-qualifiers> ::= [r] [V] [K] */
+
+static void
+write_nested_name (const tree decl)
+{
+ tree template_info;
+
+ MANGLE_TRACE_TREE ("nested-name", decl);
+
+ write_char ('N');
+
+ /* Write CV-qualifiers, if this is a member function. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+ {
+ if (DECL_VOLATILE_MEMFUNC_P (decl))
+ write_char ('V');
+ if (DECL_CONST_MEMFUNC_P (decl))
+ write_char ('K');
+ }
+
+ /* Is this a template instance? */
+ if (decl_is_template_id (decl, &template_info))
+ {
+ /* Yes, use <template-prefix>. */
+ write_template_prefix (decl);
+ write_template_args (TI_ARGS (template_info));
+ }
+ else
+ {
+ /* No, just use <prefix> */
+ write_prefix (DECL_CONTEXT (decl));
+ write_unqualified_name (decl);
+ }
+ write_char ('E');
+}
+
+/* <prefix> ::= <prefix> <unqualified-name>
+ ::= <template-param>
+ ::= <template-prefix> <template-args>
+ ::= # empty
+ ::= <substitution> */
+
+static void
+write_prefix (const tree node)
+{
+ tree decl;
+ /* Non-NULL if NODE represents a template-id. */
+ tree template_info = NULL;
+
+ MANGLE_TRACE_TREE ("prefix", node);
+
+ if (node == NULL
+ || node == global_namespace)
+ return;
+
+ if (find_substitution (node))
+ return;
+
+ if (DECL_P (node))
+ {
+ /* If this is a function decl, that means we've hit function
+ scope, so this prefix must be for a local name. In this
+ case, we're under the <local-name> production, which encodes
+ the enclosing function scope elsewhere. So don't continue
+ here. */
+ if (TREE_CODE (node) == FUNCTION_DECL)
+ return;
+
+ decl = node;
+ decl_is_template_id (decl, &template_info);
+ }
+ else
+ {
+ /* Node is a type. */
+ decl = TYPE_NAME (node);
+ if (CLASSTYPE_TEMPLATE_ID_P (node))
+ template_info = TYPE_TEMPLATE_INFO (node);
+ }
+
+ /* In G++ 3.2, the name of the template parameter was used. */
+ if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
+ && !abi_version_at_least (2))
+ G.need_abi_warning = true;
+
+ if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
+ && abi_version_at_least (2))
+ write_template_param (node);
+ else if (template_info != NULL)
+ /* Templated. */
+ {
+ write_template_prefix (decl);
+ write_template_args (TI_ARGS (template_info));
+ }
+ else
+ /* Not templated. */
+ {
+ write_prefix (CP_DECL_CONTEXT (decl));
+ write_unqualified_name (decl);
+ }
+
+ add_substitution (node);
+}
+
+/* <template-prefix> ::= <prefix> <template component>
+ ::= <template-param>
+ ::= <substitution> */
+
+static void
+write_template_prefix (const tree node)
+{
+ tree decl = DECL_P (node) ? node : TYPE_NAME (node);
+ tree type = DECL_P (node) ? TREE_TYPE (node) : node;
+ tree context = CP_DECL_CONTEXT (decl);
+ tree template_info;
+ tree template;
+ tree substitution;
+
+ MANGLE_TRACE_TREE ("template-prefix", node);
+
+ /* Find the template decl. */
+ if (decl_is_template_id (decl, &template_info))
+ template = TI_TEMPLATE (template_info);
+ else
+ {
+ 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
+ instantiated. For instance, consider
+
+ template<typename T> struct Outer {
+ template<typename U> struct Inner {};
+ };
+
+ The template name for `Inner' in `Outer<int>::Inner<float>' is
+ `Outer<int>::Inner<U>'. In g++, we don't instantiate the template
+ levels separately, so there's no TEMPLATE_DECL available for this
+ (there's only `Outer<T>::Inner<U>').
+
+ In order to get the substitutions right, we create a special
+ TREE_LIST to represent the substitution candidate for a nested
+ template. The TREE_PURPOSE is the template's context, fully
+ instantiated, and the TREE_VALUE is the TEMPLATE_DECL for the inner
+ template.
+
+ So, for the example above, `Outer<int>::Inner' is represented as a
+ substitution candidate by a TREE_LIST whose purpose is `Outer<int>'
+ and whose value is `Outer<T>::Inner<U>'. */
+ if (TYPE_P (context))
+ substitution = build_tree_list (context, template);
+ else
+ substitution = template;
+
+ if (find_substitution (substitution))
+ return;
+
+ /* In G++ 3.2, the name of the template template parameter was used. */
+ if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+ && !abi_version_at_least (2))
+ G.need_abi_warning = true;
+
+ if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+ && abi_version_at_least (2))
+ write_template_param (TREE_TYPE (template));
+ else
+ {
+ write_prefix (context);
+ write_unqualified_name (decl);
+ }
+
+ add_substitution (substitution);
+}
+
+/* We don't need to handle thunks, vtables, or VTTs here. Those are
+ mangled through special entry points.
+
+ <unqualified-name> ::= <operator-name>
+ ::= <special-name>
+ APPLE LOCAL begin mainline 2007-05-09 5173149
+ ::= <source-name>
+ ::= <local-source-name>
+
+ <local-source-name> ::= L <source-name> <discriminator> */
+
+/* APPLE LOCAL end mainline 2007-05-09 5173149 */ \
+static void
+write_unqualified_name (const tree decl)
+{
+ MANGLE_TRACE_TREE ("unqualified-name", decl);
+
+ if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_CONSTRUCTOR_P (decl))
+ 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.
+ <operator> ::= cv <type> */
+ tree type;
+ if (decl_is_template_id (decl, NULL))
+ {
+ 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
+ type = DECL_CONV_FN_TYPE (decl);
+ write_conversion_operator_name (type);
+ }
+ else if (DECL_OVERLOADED_OPERATOR_P (decl))
+ {
+ operator_name_info_t *oni;
+ if (DECL_ASSIGNMENT_OPERATOR_P (decl))
+ oni = assignment_operator_name_info;
+ else
+ oni = operator_name_info;
+
+ write_string (oni[DECL_OVERLOADED_OPERATOR_P (decl)].mangled_name);
+ }
+/* APPLE LOCAL begin mainline 2007-05-09 5173149 */ \
+ else if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
+ && DECL_NAMESPACE_SCOPE_P (decl)
+ && decl_linkage (decl) == lk_internal)
+ {
+ MANGLE_TRACE_TREE ("local-source-name", decl);
+ write_char ('L');
+ write_source_name (DECL_NAME (decl));
+ /* The default discriminator is 1, and that's all we ever use,
+ so there's no code to output one here. */
+ }
+/* APPLE LOCAL end mainline 2007-05-09 5173149 */ \
+ else
+ write_source_name (DECL_NAME (decl));
+}
+
+/* Write the unqualified-name for a conversion operator to TYPE. */
+
+static void
+write_conversion_operator_name (const tree type)
+{
+ write_string ("cv");
+ write_type (type);
+}
+
+/* Non-terminal <source-name>. IDENTIFIER is an IDENTIFIER_NODE.
+
+ <source-name> ::= </length/ number> <identifier> */
+
+static void
+write_source_name (tree identifier)
+{
+ MANGLE_TRACE_TREE ("source-name", identifier);
+
+ /* Never write the whole template-id name including the template
+ arguments; we only want the template name. */
+ if (IDENTIFIER_TEMPLATE (identifier))
+ identifier = IDENTIFIER_TEMPLATE (identifier);
+
+ write_unsigned_number (IDENTIFIER_LENGTH (identifier));
+ write_identifier (IDENTIFIER_POINTER (identifier));
+}
+
+/* Convert NUMBER to ascii using base BASE and generating at least
+ MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
+ into which to store the characters. Returns the number of
+ characters generated (these will be layed out in advance of where
+ BUFFER points). */
+
+static int
+hwint_to_ascii (unsigned HOST_WIDE_INT number, const unsigned int base,
+ char *buffer, const unsigned int min_digits)
+{
+ static const char base_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ unsigned digits = 0;
+
+ while (number)
+ {
+ unsigned HOST_WIDE_INT d = number / base;
+
+ *--buffer = base_digits[number - d * base];
+ digits++;
+ number = d;
+ }
+ while (digits < min_digits)
+ {
+ *--buffer = base_digits[0];
+ digits++;
+ }
+ return digits;
+}
+
+/* Non-terminal <number>.
+
+ <number> ::= [n] </decimal integer/> */
+
+static void
+write_number (unsigned HOST_WIDE_INT number, const int unsigned_p,
+ const unsigned int base)
+{
+ char buffer[sizeof (HOST_WIDE_INT) * 8];
+ unsigned count = 0;
+
+ if (!unsigned_p && (HOST_WIDE_INT) number < 0)
+ {
+ write_char ('n');
+ number = -((HOST_WIDE_INT) number);
+ }
+ count = hwint_to_ascii (number, base, buffer + sizeof (buffer), 1);
+ write_chars (buffer + sizeof (buffer) - count, count);
+}
+
+/* Write out an integral CST in decimal. Most numbers are small, and
+ representable in a HOST_WIDE_INT. Occasionally we'll have numbers
+ bigger than that, which we must deal with. */
+
+static inline void
+write_integer_cst (const tree cst)
+{
+ int sign = tree_int_cst_sgn (cst);
+
+ if (TREE_INT_CST_HIGH (cst) + (sign < 0))
+ {
+ /* A bignum. We do this in chunks, each of which fits in a
+ HOST_WIDE_INT. */
+ char buffer[sizeof (HOST_WIDE_INT) * 8 * 2];
+ unsigned HOST_WIDE_INT chunk;
+ unsigned chunk_digits;
+ char *ptr = buffer + sizeof (buffer);
+ unsigned count = 0;
+ tree n, base, type;
+ int done;
+
+ /* HOST_WIDE_INT must be at least 32 bits, so 10^9 is
+ representable. */
+ chunk = 1000000000;
+ chunk_digits = 9;
+
+ if (sizeof (HOST_WIDE_INT) >= 8)
+ {
+ /* It is at least 64 bits, so 10^18 is representable. */
+ chunk_digits = 18;
+ chunk *= chunk;
+ }
+
+ type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
+ 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)
+ {
+ write_char ('n');
+ n = fold_build1 (NEGATE_EXPR, type, n);
+ }
+ do
+ {
+ 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_build2 (MINUS_EXPR, type, n, tmp);
+ c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
+ done ? 1 : chunk_digits);
+ ptr -= c;
+ count += c;
+ n = d;
+ }
+ while (!done);
+ write_chars (ptr, count);
+ }
+ else
+ {
+ /* A small num. */
+ unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
+
+ if (sign < 0)
+ {
+ write_char ('n');
+ low = -low;
+ }
+ write_unsigned_number (low);
+ }
+}
+
+/* Write out a floating-point literal.
+
+ "Floating-point literals are encoded using the bit pattern of the
+ target processor's internal representation of that number, as a
+ fixed-length lowercase hexadecimal string, high-order bytes first
+ (even if the target processor would store low-order bytes first).
+ The "n" prefix is not used for floating-point literals; the sign
+ bit is encoded with the rest of the number.
+
+ Here are some examples, assuming the IEEE standard representation
+ for floating point numbers. (Spaces are for readability, not
+ part of the encoding.)
+
+ 1.0f Lf 3f80 0000 E
+ -1.0f Lf bf80 0000 E
+ 1.17549435e-38f Lf 0080 0000 E
+ 1.40129846e-45f Lf 0000 0001 E
+ 0.0f Lf 0000 0000 E"
+
+ Caller is responsible for the Lx and the E. */
+static void
+write_real_cst (const tree value)
+{
+ if (abi_version_at_least (2))
+ {
+ long target_real[4]; /* largest supported float */
+ char buffer[9]; /* eight hex digits in a 32-bit number */
+ int i, limit, dir;
+
+ tree type = TREE_TYPE (value);
+ int words = GET_MODE_BITSIZE (TYPE_MODE (type)) / 32;
+
+ real_to_target (target_real, &TREE_REAL_CST (value),
+ TYPE_MODE (type));
+
+ /* The value in target_real is in the target word order,
+ so we must write it out backward if that happens to be
+ little-endian. write_number cannot be used, it will
+ produce uppercase. */
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ i = 0, limit = words, dir = 1;
+ else
+ i = words - 1, limit = -1, dir = -1;
+
+ for (; i != limit; i += dir)
+ {
+ sprintf (buffer, "%08lx", target_real[i]);
+ write_chars (buffer, 8);
+ }
+ }
+ else
+ {
+ /* In G++ 3.3 and before the REAL_VALUE_TYPE was written out
+ literally. Note that compatibility with 3.2 is impossible,
+ because the old floating-point emulator used a different
+ format for REAL_VALUE_TYPE. */
+ size_t i;
+ for (i = 0; i < sizeof (TREE_REAL_CST (value)); ++i)
+ write_number (((unsigned char *) &TREE_REAL_CST (value))[i],
+ /*unsigned_p*/ 1,
+ /*base*/ 16);
+ G.need_abi_warning = 1;
+ }
+}
+
+/* Non-terminal <identifier>.
+
+ <identifier> ::= </unqualified source code identifier> */
+
+static void
+write_identifier (const char *identifier)
+{
+ MANGLE_TRACE ("identifier", identifier);
+ write_string (identifier);
+}
+
+/* Handle constructor productions of non-terminal <special-name>.
+ CTOR is a constructor FUNCTION_DECL.
+
+ <special-name> ::= C1 # complete object constructor
+ ::= C2 # base object constructor
+ ::= C3 # complete object allocating constructor
+
+ Currently, allocating constructors are never used.
+
+ APPLE LOCAL decloning
+ Deleted comment. */
+
+static void
+write_special_name_constructor (const tree ctor)
+{
+ if (DECL_BASE_CONSTRUCTOR_P (ctor))
+ write_string ("C2");
+ /* APPLE LOCAL begin decloning */
+ /* This is the old-style "[unified]" constructor. */
+ else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
+ write_string ("C4");
+ /* APPLE LOCAL end decloning */
+ else
+ {
+ 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>.
+ DTOR is a destructor FUNCTION_DECL.
+
+ <special-name> ::= D0 # deleting (in-charge) destructor
+ ::= D1 # complete object (in-charge) destructor
+ ::= D2 # base object (not-in-charge) destructor
+
+ We also need to provide mangled names for the maybe-incharge
+ destructor, so we treat it here too. mangle_decl_string will
+ append *INTERNAL* to that, to make sure we never emit it. */
+
+static void
+write_special_name_destructor (const tree dtor)
+{
+ if (DECL_DELETING_DESTRUCTOR_P (dtor))
+ write_string ("D0");
+ else if (DECL_BASE_DESTRUCTOR_P (dtor))
+ write_string ("D2");
+ /* APPLE LOCAL begin decloning */
+ else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
+ /* This is the old-style "[unified]" destructor. */
+ write_string ("D4");
+ /* APPLE LOCAL end decloning */
+ else
+ {
+ 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
+ FUNCTION. The discriminator is the lexical ordinal of VAR among
+ entities with the same name in the same FUNCTION. */
+
+static int
+discriminator_for_local_entity (tree entity)
+{
+ /* Assume this is the only local entity with this name. */
+ int discriminator = 0;
+
+ if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
+ discriminator = DECL_DISCRIMINATOR (entity);
+ else if (TREE_CODE (entity) == TYPE_DECL)
+ {
+ int ix;
+
+ /* Scan the list of local classes. */
+ entity = TREE_TYPE (entity);
+ for (ix = 0; ; ix++)
+ {
+ tree type = VEC_index (tree, local_classes, ix);
+ if (type == entity)
+ break;
+ /* APPLE LOCAL begin anon types 6822746 */
+ if (TYPE_MAIN_DECL (type) == TYPE_MAIN_DECL (entity))
+ break;
+ /* APPLE LOCAL end anon types 6822746 */
+ if (TYPE_IDENTIFIER (type) == TYPE_IDENTIFIER (entity)
+ && TYPE_CONTEXT (type) == TYPE_CONTEXT (entity))
+ ++discriminator;
+ }
+ }
+
+ return discriminator;
+}
+
+/* Return the discriminator for STRING, a string literal used inside
+ FUNCTION. The discriminator is the lexical ordinal of STRING among
+ string literals used in FUNCTION. */
+
+static int
+discriminator_for_string_literal (tree function ATTRIBUTE_UNUSED,
+ tree string ATTRIBUTE_UNUSED)
+{
+ /* For now, we don't discriminate amongst string literals. */
+ return 0;
+}
+
+/* <discriminator> := _ <number>
+
+ The discriminator is used only for the second and later occurrences
+ of the same name within a single function. In this case <number> is
+ n - 2, if this is the nth occurrence, in lexical order. */
+
+static void
+write_discriminator (const int discriminator)
+{
+ /* If discriminator is zero, don't write anything. Otherwise... */
+ if (discriminator > 0)
+ {
+ write_char ('_');
+ write_unsigned_number (discriminator - 1);
+ }
+}
+
+/* Mangle the name of a function-scope entity. FUNCTION is the
+ FUNCTION_DECL for the enclosing function. ENTITY is the decl for
+ the entity itself. LOCAL_ENTITY is the entity that's directly
+ scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope
+ of ENTITY.
+
+ <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ := Z <function encoding> E s [<discriminator>] */
+
+static void
+write_local_name (const tree function, const tree local_entity,
+ const tree entity)
+{
+ MANGLE_TRACE_TREE ("local-name", entity);
+
+ write_char ('Z');
+ write_encoding (function);
+ write_char ('E');
+ if (TREE_CODE (entity) == STRING_CST)
+ {
+ write_char ('s');
+ write_discriminator (discriminator_for_string_literal (function,
+ entity));
+ }
+ else
+ {
+ /* Now the <entity name>. Let write_name know its being called
+ from <local-name>, so it doesn't try to process the enclosing
+ function scope again. */
+ write_name (entity, /*ignore_local_scope=*/1);
+ write_discriminator (discriminator_for_local_entity (local_entity));
+ }
+}
+
+/* Non-terminals <type> and <CV-qualifier>.
+
+ <type> ::= <builtin-type>
+ ::= <function-type>
+ ::= <class-enum-type>
+ ::= <array-type>
+ ::= <pointer-to-member-type>
+ ::= <template-param>
+ ::= <substitution>
+ ::= <CV-qualifier>
+ ::= P <type> # pointer-to
+ ::= R <type> # reference-to
+ ::= C <type> # complex pair (C 2000)
+ ::= G <type> # imaginary (C 2000) [not supported]
+ ::= U <source-name> <type> # vendor extended type qualifier
+
+ TYPE is a type node. */
+
+static void
+write_type (tree type)
+{
+ /* This gets set to nonzero if TYPE turns out to be a (possibly
+ CV-qualified) builtin type. */
+ int is_builtin_type = 0;
+
+ MANGLE_TRACE_TREE ("type", type);
+
+ if (type == error_mark_node)
+ return;
+
+ if (find_substitution (type))
+ return;
+
+ if (write_CV_qualifiers_for_type (type) > 0)
+ /* If TYPE was CV-qualified, we just wrote the qualifiers; now
+ mangle the unqualified type. The recursive call is needed here
+ since both the qualified and unqualified types are substitution
+ candidates. */
+ write_type (TYPE_MAIN_VARIANT (type));
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ /* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
+ so that the cv-qualification of the element type is available
+ in write_array_type. */
+ write_array_type (type);
+ else
+ {
+ /* APPLE LOCAL begin mangle_type 7105099 */
+ tree type_orig = type;
+
+ /* See through any typedefs. */
+ type = TYPE_MAIN_VARIANT (type);
+
+ if (TYPE_PTRMEM_P (type))
+ write_pointer_to_member_type (type);
+ else
+ {
+ /* Handle any target-specific fundamental types. */
+ const char *target_mangling
+ = targetm.mangle_type (type_orig);
+
+ if (target_mangling)
+ {
+ write_string (target_mangling);
+ return;
+ }
+
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ case INTEGER_TYPE: /* Includes wchar_t. */
+ case REAL_TYPE:
+ {
+ /* 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');
+ write_type (TREE_TYPE (type));
+ break;
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ write_function_type (type);
+ break;
+
+ case UNION_TYPE:
+ case RECORD_TYPE:
+ case ENUMERAL_TYPE:
+ /* A pointer-to-member function is represented as a special
+ RECORD_TYPE, so check for this first. */
+ if (TYPE_PTRMEMFUNC_P (type))
+ write_pointer_to_member_type (type);
+ else
+ write_class_enum_type (type);
+ break;
+
+ case TYPENAME_TYPE:
+ case UNBOUND_CLASS_TEMPLATE:
+ /* We handle TYPENAME_TYPEs and UNBOUND_CLASS_TEMPLATEs like
+ ordinary nested names. */
+ write_nested_name (TYPE_STUB_DECL (type));
+ break;
+
+ case POINTER_TYPE:
+ write_char ('P');
+ write_type (TREE_TYPE (type));
+ break;
+
+ /* APPLE LOCAL begin blocks 6040305 */
+ case BLOCK_POINTER_TYPE:
+ write_string ("U13block_pointer");
+ write_type (TREE_TYPE (type));
+ break;
+ /* APPLE LOCAL end blocks 6040305 */
+
+ case REFERENCE_TYPE:
+ write_char ('R');
+ write_type (TREE_TYPE (type));
+ break;
+
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_PARM_INDEX:
+ write_template_param (type);
+ break;
+
+ case TEMPLATE_TEMPLATE_PARM:
+ write_template_template_param (type);
+ break;
+
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ write_template_template_param (type);
+ write_template_args
+ (TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type)));
+ break;
+
+ case VECTOR_TYPE:
+ write_string ("U8__vector");
+ write_type (TREE_TYPE (type));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ /* APPLE LOCAL end mangle_type 7105099 */
+ }
+
+ /* Types other than builtin types are substitution candidates. */
+ if (!is_builtin_type)
+ add_substitution (type);
+}
+
+/* Non-terminal <CV-qualifiers> for type nodes. Returns the number of
+ CV-qualifiers written for TYPE.
+
+ <CV-qualifiers> ::= [r] [V] [K] */
+
+static int
+write_CV_qualifiers_for_type (const tree type)
+{
+ int num_qualifiers = 0;
+
+ /* The order is specified by:
+
+ "In cases where multiple order-insensitive qualifiers are
+ present, they should be ordered 'K' (closest to the base type),
+ 'V', 'r', and 'U' (farthest from the base type) ..."
+
+ Note that we do not use cp_type_quals below; given "const
+ int[3]", the "const" is emitted with the "int", not with the
+ array. */
+
+ if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
+ {
+ write_char ('r');
+ ++num_qualifiers;
+ }
+ if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+ {
+ write_char ('V');
+ ++num_qualifiers;
+ }
+ if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
+ {
+ write_char ('K');
+ ++num_qualifiers;
+ }
+
+ return num_qualifiers;
+}
+
+/* Non-terminal <builtin-type>.
+
+ <builtin-type> ::= v # void
+ ::= b # bool
+ ::= w # wchar_t
+ ::= c # char
+ ::= a # signed char
+ ::= h # unsigned char
+ ::= s # short
+ ::= t # unsigned short
+ ::= i # int
+ ::= j # unsigned int
+ ::= l # long
+ ::= m # unsigned long
+ ::= x # long long, __int64
+ ::= y # unsigned long long, __int64
+ ::= n # __int128
+ ::= o # unsigned __int128
+ ::= f # float
+ ::= d # double
+ ::= e # long double, __float80
+ ::= g # __float128 [not supported]
+ ::= u <source-name> # vendor extended type */
+
+static void
+write_builtin_type (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ write_char ('v');
+ break;
+
+ case BOOLEAN_TYPE:
+ write_char ('b');
+ break;
+
+ case INTEGER_TYPE:
+ /* If this is size_t, get the underlying int type. */
+ if (TYPE_IS_SIZETYPE (type))
+ type = TYPE_DOMAIN (type);
+
+ /* TYPE may still be wchar_t, since that isn't in
+ integer_type_nodes. */
+ if (type == wchar_type_node)
+ write_char ('w');
+ else if (TYPE_FOR_JAVA (type))
+ write_java_integer_type_codes (type);
+ else
+ {
+ size_t itk;
+ /* Assume TYPE is one of the shared integer type nodes. Find
+ it in the array of these nodes. */
+ iagain:
+ for (itk = 0; itk < itk_none; ++itk)
+ if (type == integer_types[itk])
+ {
+ /* Print the corresponding single-letter code. */
+ write_char (integer_type_codes[itk]);
+ break;
+ }
+
+ if (itk == itk_none)
+ {
+ tree t = c_common_type_for_mode (TYPE_MODE (type),
+ TYPE_UNSIGNED (type));
+ if (type != t)
+ {
+ type = t;
+ goto iagain;
+ }
+
+ if (TYPE_PRECISION (type) == 128)
+ write_char (TYPE_UNSIGNED (type) ? 'o' : 'n');
+ else
+ {
+ /* Allow for cases where TYPE is not one of the shared
+ integer type nodes and write a "vendor extended builtin
+ type" with a name the form intN or uintN, respectively.
+ Situations like this can happen if you have an
+ __attribute__((__mode__(__SI__))) type and use exotic
+ switches like '-mint8' on AVR. Of course, this is
+ undefined by the C++ ABI (and '-mint8' is not even
+ Standard C conforming), but when using such special
+ options you're pretty much in nowhere land anyway. */
+ const char *prefix;
+ char prec[11]; /* up to ten digits for an unsigned */
+
+ prefix = TYPE_UNSIGNED (type) ? "uint" : "int";
+ sprintf (prec, "%u", (unsigned) TYPE_PRECISION (type));
+ write_char ('u'); /* "vendor extended builtin type" */
+ write_unsigned_number (strlen (prefix) + strlen (prec));
+ write_string (prefix);
+ write_string (prec);
+ }
+ }
+ }
+ break;
+
+ case REAL_TYPE:
+ if (type == float_type_node
+ || type == java_float_type_node)
+ write_char ('f');
+ else if (type == double_type_node
+ || type == java_double_type_node)
+ write_char ('d');
+ else if (type == long_double_type_node)
+ write_char ('e');
+ else
+ gcc_unreachable ();
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Non-terminal <function-type>. NODE is a FUNCTION_TYPE or
+ METHOD_TYPE. The return type is mangled before the parameter
+ types.
+
+ <function-type> ::= F [Y] <bare-function-type> E */
+
+static void
+write_function_type (const tree type)
+{
+ MANGLE_TRACE_TREE ("function-type", type);
+
+ /* For a pointer to member function, the function type may have
+ cv-qualifiers, indicating the quals for the artificial 'this'
+ parameter. */
+ if (TREE_CODE (type) == METHOD_TYPE)
+ {
+ /* The first parameter must be a POINTER_TYPE pointing to the
+ `this' parameter. */
+ tree this_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
+ write_CV_qualifiers_for_type (this_type);
+ }
+
+ write_char ('F');
+ /* We don't track whether or not a type is `extern "C"'. Note that
+ you can have an `extern "C"' function that does not have
+ `extern "C"' type, and vice versa:
+
+ extern "C" typedef void function_t();
+ function_t f; // f has C++ linkage, but its type is
+ // `extern "C"'
+
+ typedef void function_t();
+ extern "C" function_t f; // Vice versa.
+
+ See [dcl.link]. */
+ write_bare_function_type (type, /*include_return_type_p=*/1,
+ /*decl=*/NULL);
+ write_char ('E');
+}
+
+/* Non-terminal <bare-function-type>. TYPE is a FUNCTION_TYPE or
+ METHOD_TYPE. If INCLUDE_RETURN_TYPE is nonzero, the return value
+ is mangled before the parameter types. If non-NULL, DECL is
+ FUNCTION_DECL for the function whose type is being emitted.
+
+ If DECL is a member of a Java type, then a literal 'J'
+ is output and the return type is mangled as if INCLUDE_RETURN_TYPE
+ were nonzero.
+
+ <bare-function-type> ::= [J]</signature/ type>+ */
+
+static void
+write_bare_function_type (const tree type, const int include_return_type_p,
+ const tree decl)
+{
+ int java_method_p;
+
+ MANGLE_TRACE_TREE ("bare-function-type", type);
+
+ /* Detect Java methods and emit special encoding. */
+ if (decl != NULL
+ && DECL_FUNCTION_MEMBER_P (decl)
+ && TYPE_FOR_JAVA (DECL_CONTEXT (decl))
+ && !DECL_CONSTRUCTOR_P (decl)
+ && !DECL_DESTRUCTOR_P (decl)
+ && !DECL_CONV_FN_P (decl))
+ {
+ java_method_p = 1;
+ write_char ('J');
+ }
+ else
+ {
+ java_method_p = 0;
+ }
+
+ /* Mangle the return type, if requested. */
+ if (include_return_type_p || java_method_p)
+ write_type (TREE_TYPE (type));
+
+ /* Now mangle the types of the arguments. */
+ write_method_parms (TYPE_ARG_TYPES (type),
+ TREE_CODE (type) == METHOD_TYPE,
+ decl);
+}
+
+/* Write the mangled representation of a method parameter list of
+ types given in PARM_TYPES. If METHOD_P is nonzero, the function is
+ considered a non-static method, and the this parameter is omitted.
+ If non-NULL, DECL is the FUNCTION_DECL for the function whose
+ parameters are being emitted. */
+
+static void
+write_method_parms (tree parm_types, const int method_p, const tree decl)
+{
+ tree first_parm_type;
+ tree parm_decl = decl ? DECL_ARGUMENTS (decl) : NULL_TREE;
+
+ /* Assume this parameter type list is variable-length. If it ends
+ with a void type, then it's not. */
+ int varargs_p = 1;
+
+ /* If this is a member function, skip the first arg, which is the
+ this pointer.
+ "Member functions do not encode the type of their implicit this
+ parameter."
+
+ Similarly, there's no need to mangle artificial parameters, like
+ the VTT parameters for constructors and destructors. */
+ if (method_p)
+ {
+ parm_types = TREE_CHAIN (parm_types);
+ parm_decl = parm_decl ? TREE_CHAIN (parm_decl) : NULL_TREE;
+
+ while (parm_decl && DECL_ARTIFICIAL (parm_decl))
+ {
+ parm_types = TREE_CHAIN (parm_types);
+ parm_decl = TREE_CHAIN (parm_decl);
+ }
+ }
+
+ for (first_parm_type = parm_types;
+ parm_types;
+ parm_types = TREE_CHAIN (parm_types))
+ {
+ tree parm = TREE_VALUE (parm_types);
+ if (parm == void_type_node)
+ {
+ /* "Empty parameter lists, whether declared as () or
+ conventionally as (void), are encoded with a void parameter
+ (v)." */
+ if (parm_types == first_parm_type)
+ write_type (parm);
+ /* If the parm list is terminated with a void type, it's
+ fixed-length. */
+ varargs_p = 0;
+ /* A void type better be the last one. */
+ gcc_assert (TREE_CHAIN (parm_types) == NULL);
+ }
+ else
+ write_type (parm);
+ }
+
+ if (varargs_p)
+ /* <builtin-type> ::= z # ellipsis */
+ write_char ('z');
+}
+
+/* <class-enum-type> ::= <name> */
+
+static void
+write_class_enum_type (const tree type)
+{
+ write_name (TYPE_NAME (type), /*ignore_local_scope=*/0);
+}
+
+/* Non-terminal <template-args>. ARGS is a TREE_VEC of template
+ arguments.
+
+ <template-args> ::= I <template-arg>+ E */
+
+static void
+write_template_args (tree args)
+{
+ int i;
+ int length = TREE_VEC_LENGTH (args);
+
+ MANGLE_TRACE_TREE ("template-args", args);
+
+ write_char ('I');
+
+ 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));
+
+ write_char ('E');
+}
+
+/* <expression> ::= <unary operator-name> <expression>
+ ::= <binary operator-name> <expression> <expression>
+ ::= <expr-primary>
+
+ <expr-primary> ::= <template-param>
+ ::= L <type> <value number> E # literal
+ ::= L <mangled-name> E # external name
+ ::= sr <type> <unqualified-name>
+ ::= sr <type> <unqualified-name> <template-args> */
+
+static void
+write_expression (tree expr)
+{
+ enum tree_code code;
+
+ 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);
+ }
+
+ if (code == BASELINK)
+ {
+ expr = BASELINK_FUNCTIONS (expr);
+ code = TREE_CODE (expr);
+ }
+
+ /* Handle pointers-to-members by making them look like expression
+ nodes. */
+ if (code == PTRMEM_CST)
+ {
+ expr = build_nt (ADDR_EXPR,
+ build_qualified_name (/*type=*/NULL_TREE,
+ PTRMEM_CST_CLASS (expr),
+ PTRMEM_CST_MEMBER (expr),
+ /*template_p=*/false));
+ code = TREE_CODE (expr);
+ }
+
+ /* Handle template parameters. */
+ if (code == TEMPLATE_TYPE_PARM
+ || code == TEMPLATE_TEMPLATE_PARM
+ || code == BOUND_TEMPLATE_TEMPLATE_PARM
+ || code == TEMPLATE_PARM_INDEX)
+ write_template_param (expr);
+ /* Handle literals. */
+ 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))
+ {
+ /* G++ 3.2 incorrectly mangled non-type template arguments of
+ enumeration type using their names. */
+ if (code == CONST_DECL)
+ G.need_abi_warning = 1;
+ write_char ('L');
+ write_mangled_name (expr, false);
+ write_char ('E');
+ }
+ else if (TREE_CODE (expr) == SIZEOF_EXPR
+ && TYPE_P (TREE_OPERAND (expr, 0)))
+ {
+ write_string ("st");
+ write_type (TREE_OPERAND (expr, 0));
+ }
+ else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
+ {
+ tree scope = TREE_OPERAND (expr, 0);
+ tree member = TREE_OPERAND (expr, 1);
+
+ /* If the MEMBER is a real declaration, then the qualifying
+ scope was not dependent. Ideally, we would not have a
+ SCOPE_REF in those cases, but sometimes we do. If the second
+ argument is a DECL, then the name must not have been
+ dependent. */
+ if (DECL_P (member))
+ write_expression (member);
+ else
+ {
+ tree template_args;
+
+ write_string ("sr");
+ write_type (scope);
+ /* If MEMBER is a template-id, separate the template
+ from the arguments. */
+ if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
+ {
+ template_args = TREE_OPERAND (member, 1);
+ member = TREE_OPERAND (member, 0);
+ }
+ else
+ template_args = NULL_TREE;
+ /* Write out the name of the MEMBER. */
+ if (IDENTIFIER_TYPENAME_P (member))
+ write_conversion_operator_name (TREE_TYPE (member));
+ else if (IDENTIFIER_OPNAME_P (member))
+ {
+ int i;
+ const char *mangled_name = NULL;
+
+ /* Unfortunately, there is no easy way to go from the
+ name of the operator back to the corresponding tree
+ code. */
+ for (i = 0; i < LAST_CPLUS_TREE_CODE; ++i)
+ if (operator_name_info[i].identifier == member)
+ {
+ /* The ABI says that we prefer binary operator
+ names to unary operator names. */
+ if (operator_name_info[i].arity == 2)
+ {
+ mangled_name = operator_name_info[i].mangled_name;
+ break;
+ }
+ else if (!mangled_name)
+ mangled_name = operator_name_info[i].mangled_name;
+ }
+ else if (assignment_operator_name_info[i].identifier
+ == member)
+ {
+ mangled_name
+ = assignment_operator_name_info[i].mangled_name;
+ break;
+ }
+ write_string (mangled_name);
+ }
+ else
+ write_source_name (member);
+ /* Write out the template arguments. */
+ if (template_args)
+ write_template_args (template_args);
+ }
+ }
+ else
+ {
+ int i;
+
+ /* When we bind a variable or function to a non-type template
+ argument with reference type, we create an ADDR_EXPR to show
+ the fact that the entity's address has been taken. But, we
+ don't actually want to output a mangling code for the `&'. */
+ if (TREE_CODE (expr) == ADDR_EXPR
+ && TREE_TYPE (expr)
+ && TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ if (DECL_P (expr))
+ {
+ write_expression (expr);
+ return;
+ }
+
+ code = TREE_CODE (expr);
+ }
+
+ /* If it wasn't any of those, recursively expand the expression. */
+ write_string (operator_name_info[(int) code].mangled_name);
+
+ switch (code)
+ {
+ case CALL_EXPR:
+ sorry ("call_expr cannot be mangled due to a defect in the C++ ABI");
+ break;
+
+ case CAST_EXPR:
+ write_type (TREE_TYPE (expr));
+ /* 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:
+ case CONST_CAST_EXPR:
+ write_type (TREE_TYPE (expr));
+ write_expression (TREE_OPERAND (expr, 0));
+ break;
+
+
+ /* Handle pointers-to-members specially. */
+ case SCOPE_REF:
+ write_type (TREE_OPERAND (expr, 0));
+ if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
+ write_source_name (TREE_OPERAND (expr, 1));
+ else if (TREE_CODE (TREE_OPERAND (expr, 1)) == TEMPLATE_ID_EXPR)
+ {
+ tree template_id;
+ tree name;
+
+ template_id = TREE_OPERAND (expr, 1);
+ name = TREE_OPERAND (template_id, 0);
+ /* FIXME: What about operators? */
+ gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
+ write_source_name (TREE_OPERAND (template_id, 0));
+ write_template_args (TREE_OPERAND (template_id, 1));
+ }
+ else
+ {
+ /* G++ 3.2 incorrectly put out both the "sr" code and
+ the nested name of the qualified name. */
+ G.need_abi_warning = 1;
+ write_encoding (TREE_OPERAND (expr, 1));
+ }
+ break;
+
+ default:
+ for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
+ {
+ tree operand = TREE_OPERAND (expr, i);
+ /* As a GNU extension, 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);
+ }
+ }
+ }
+}
+
+/* Literal subcase of non-terminal <template-arg>.
+
+ "Literal arguments, e.g. "A<42L>", are encoded with their type
+ and value. Negative integer values are preceded with "n"; for
+ example, "A<-42L>" becomes "1AILln42EE". The bool value false is
+ encoded as 0, true as 1." */
+
+static void
+write_template_arg_literal (const tree value)
+{
+ write_char ('L');
+ write_type (TREE_TYPE (value));
+
+ switch (TREE_CODE (value))
+ {
+ 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 <template-arg>.
+
+ <template-arg> ::= <type> # type
+ ::= L <type> </value/ number> E # literal
+ ::= LZ <name> E # external name
+ ::= X <expression> E # expression */
+
+static void
+write_template_arg (tree node)
+{
+ enum tree_code code = TREE_CODE (node);
+
+ MANGLE_TRACE_TREE ("template-arg", node);
+
+ /* A template template parameter's argument list contains TREE_LIST
+ nodes of which the value field is the actual argument. */
+ if (code == TREE_LIST)
+ {
+ node = TREE_VALUE (node);
+ /* If it's a decl, deal with its type instead. */
+ if (DECL_P (node))
+ {
+ node = TREE_TYPE (node);
+ 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) == tcc_constant && code != PTRMEM_CST)
+ || (abi_version_at_least (2) && code == CONST_DECL))
+ write_template_arg_literal (node);
+ else if (DECL_P (node))
+ {
+ /* 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');
+ /* 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');
+ }
+ else
+ {
+ /* Template arguments may be expressions. */
+ write_char ('X');
+ write_expression (node);
+ write_char ('E');
+ }
+}
+
+/* <template-template-arg>
+ ::= <name>
+ ::= <substitution> */
+
+static void
+write_template_template_arg (const tree decl)
+{
+ MANGLE_TRACE_TREE ("template-template-arg", decl);
+
+ if (find_substitution (decl))
+ return;
+ write_name (decl, /*ignore_local_scope=*/0);
+ add_substitution (decl);
+}
+
+
+/* Non-terminal <array-type>. TYPE is an ARRAY_TYPE.
+
+ <array-type> ::= A [</dimension/ number>] _ </element/ type>
+ ::= A <expression> _ </element/ type>
+
+ "Array types encode the dimension (number of elements) and the
+ element type. For variable length arrays, the dimension (but not
+ the '_' separator) is omitted." */
+
+static void
+write_array_type (const tree type)
+{
+ write_char ('A');
+ if (TYPE_DOMAIN (type))
+ {
+ tree index_type;
+ tree max;
+
+ index_type = TYPE_DOMAIN (type);
+ /* The INDEX_TYPE gives the upper and lower bounds of the
+ array. */
+ max = TYPE_MAX_VALUE (index_type);
+ if (TREE_CODE (max) == INTEGER_CST)
+ {
+ /* The ABI specifies that we should mangle the number of
+ elements in the array, not the largest allowed index. */
+ max = size_binop (PLUS_EXPR, max, size_one_node);
+ write_unsigned_number (tree_low_cst (max, 1));
+ }
+ else
+ {
+ 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));
+}
+
+/* Non-terminal <pointer-to-member-type> for pointer-to-member
+ variables. TYPE is a pointer-to-member POINTER_TYPE.
+
+ <pointer-to-member-type> ::= M </class/ type> </member/ type> */
+
+static void
+write_pointer_to_member_type (const tree type)
+{
+ write_char ('M');
+ write_type (TYPE_PTRMEM_CLASS_TYPE (type));
+ write_type (TYPE_PTRMEM_POINTED_TO_TYPE (type));
+}
+
+/* Non-terminal <template-param>. PARM is a TEMPLATE_TYPE_PARM,
+ TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
+ TEMPLATE_PARM_INDEX.
+
+ <template-param> ::= T </parameter/ number> _ */
+
+static void
+write_template_param (const tree parm)
+{
+ int parm_index;
+ int parm_level;
+ tree parm_type = NULL_TREE;
+
+ MANGLE_TRACE_TREE ("template-parm", parm);
+
+ switch (TREE_CODE (parm))
+ {
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ parm_index = TEMPLATE_TYPE_IDX (parm);
+ parm_level = TEMPLATE_TYPE_LEVEL (parm);
+ break;
+
+ case TEMPLATE_PARM_INDEX:
+ parm_index = TEMPLATE_PARM_IDX (parm);
+ parm_level = TEMPLATE_PARM_LEVEL (parm);
+ parm_type = TREE_TYPE (TEMPLATE_PARM_DECL (parm));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ write_char ('T');
+ /* NUMBER as it appears in the mangling is (-1)-indexed, with the
+ earliest template param denoted by `_'. */
+ if (parm_index > 0)
+ write_unsigned_number (parm_index - 1);
+ write_char ('_');
+}
+
+/* <template-template-param>
+ ::= <template-param>
+ ::= <substitution> */
+
+static void
+write_template_template_param (const tree parm)
+{
+ tree template = NULL_TREE;
+
+ /* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
+ template template parameter. The substitution candidate here is
+ only the template. */
+ if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ {
+ template
+ = TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
+ if (find_substitution (template))
+ return;
+ }
+
+ /* <template-param> encodes only the template parameter position,
+ not its template arguments, which is fine here. */
+ write_template_param (parm);
+ if (template)
+ add_substitution (template);
+}
+
+/* Non-terminal <substitution>.
+
+ <substitution> ::= S <seq-id> _
+ ::= S_ */
+
+static void
+write_substitution (const int seq_id)
+{
+ MANGLE_TRACE ("substitution", "");
+
+ write_char ('S');
+ if (seq_id > 0)
+ write_number (seq_id - 1, /*unsigned=*/1, 36);
+ write_char ('_');
+}
+
+/* Start mangling ENTITY. */
+
+static inline void
+start_mangling (const tree entity, const bool ident_p)
+{
+ G.entity = entity;
+ G.need_abi_warning = false;
+ 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
+ true, and the name of G.entity will be mangled differently in a
+ future version of the ABI, issue a warning. */
+
+static inline const char *
+finish_mangling (const bool warn)
+{
+ if (warn_abi && warn && G.need_abi_warning)
+ warning (OPT_Wabi, "the mangled name of %qD will change in a future "
+ "version of GCC",
+ G.entity);
+
+ /* Clear all the substitutions. */
+ VEC_truncate (tree, G.substitutions, 0);
+
+ /* Null-terminate the string. */
+ write_char ('\0');
+
+ return (const char *) obstack_finish (mangle_obstack);
+}
+
+/* Initialize data structures for mangling. */
+
+void
+init_mangle (void)
+{
+ gcc_obstack_init (&name_obstack);
+ name_base = obstack_alloc (&name_obstack, 0);
+ G.substitutions = NULL;
+
+ /* Cache these identifiers for quick comparison when checking for
+ standard substitutions. */
+ subst_identifiers[SUBID_ALLOCATOR] = get_identifier ("allocator");
+ subst_identifiers[SUBID_BASIC_STRING] = get_identifier ("basic_string");
+ subst_identifiers[SUBID_CHAR_TRAITS] = get_identifier ("char_traits");
+ subst_identifiers[SUBID_BASIC_ISTREAM] = get_identifier ("basic_istream");
+ subst_identifiers[SUBID_BASIC_OSTREAM] = get_identifier ("basic_ostream");
+ subst_identifiers[SUBID_BASIC_IOSTREAM] = get_identifier ("basic_iostream");
+}
+
+/* Generate the mangled name of DECL. */
+
+static const char *
+mangle_decl_string (const tree decl)
+{
+ const char *result;
+
+ start_mangling (decl, /*ident_p=*/true);
+
+ if (TREE_CODE (decl) == TYPE_DECL)
+ write_type (TREE_TYPE (decl));
+ else
+ 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)
+{
+ SET_DECL_ASSEMBLER_NAME (decl,
+ get_identifier_nocopy (mangle_decl_string (decl)));
+}
+
+/* Generate the mangled representation of TYPE. */
+
+const char *
+mangle_type_string (const tree type)
+{
+ const char *result;
+
+ start_mangling (type, /*ident_p=*/false);
+ write_type (type);
+ result = finish_mangling (/*warn=*/false);
+ if (DEBUG_MANGLE)
+ fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
+ return result;
+}
+
+/* Create an identifier for the mangled name of a special component
+ for belonging to TYPE. CODE is the ABI-specified code for this
+ component. */
+
+static tree
+mangle_special_for_type (const tree type, const char *code)
+{
+ const char *result;
+
+ /* 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, /*ident_p=*/true);
+
+ /* Start the mangling. */
+ write_string ("_Z");
+ write_string (code);
+
+ /* Add the type. */
+ write_type (type);
+ result = finish_mangling (/*warn=*/false);
+
+ if (DEBUG_MANGLE)
+ fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
+
+ return get_identifier_nocopy (result);
+}
+
+/* Create an identifier for the mangled representation of the typeinfo
+ structure for TYPE. */
+
+tree
+mangle_typeinfo_for_type (const tree type)
+{
+ return mangle_special_for_type (type, "TI");
+}
+
+/* Create an identifier for the mangled name of the NTBS containing
+ the mangled name of TYPE. */
+
+tree
+mangle_typeinfo_string_for_type (const tree type)
+{
+ return mangle_special_for_type (type, "TS");
+}
+
+/* Create an identifier for the mangled name of the vtable for TYPE. */
+
+tree
+mangle_vtbl_for_type (const tree type)
+{
+ return mangle_special_for_type (type, "TV");
+}
+
+/* Returns an identifier for the mangled name of the VTT for TYPE. */
+
+tree
+mangle_vtt_for_type (const tree type)
+{
+ return mangle_special_for_type (type, "TT");
+}
+
+/* Return an identifier for a construction vtable group. TYPE is
+ the most derived class in the hierarchy; BINFO is the base
+ subobject for which this construction vtable group will be used.
+
+ This mangling isn't part of the ABI specification; in the ABI
+ specification, the vtable group is dumped in the same COMDAT as the
+ main vtable, and is referenced only from that vtable, so it doesn't
+ need an external name. For binary formats without COMDAT sections,
+ though, we need external names for the vtable groups.
+
+ We use the production
+
+ <special-name> ::= CT <type> <offset number> _ <base type> */
+
+tree
+mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
+{
+ const char *result;
+
+ start_mangling (type, /*ident_p=*/true);
+
+ write_string ("_Z");
+ write_string ("TC");
+ write_type (type);
+ write_integer_cst (BINFO_OFFSET (binfo));
+ write_char ('_');
+ write_type (BINFO_TYPE (binfo));
+
+ result = finish_mangling (/*warn=*/false);
+ if (DEBUG_MANGLE)
+ fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
+ return get_identifier_nocopy (result);
+}
+
+/* Mangle a this pointer or result pointer adjustment.
+
+ <call-offset> ::= h <fixed offset number> _
+ ::= v <fixed offset number> _ <virtual offset number> _ */
+
+static void
+mangle_call_offset (const tree fixed_offset, const tree virtual_offset)
+{
+ write_char (virtual_offset ? 'v' : 'h');
+
+ /* For either flavor, write the fixed offset. */
+ write_integer_cst (fixed_offset);
+ write_char ('_');
+
+ /* For a virtual thunk, add the virtual offset. */
+ if (virtual_offset)
+ {
+ write_integer_cst (virtual_offset);
+ write_char ('_');
+ }
+}
+
+/* Return an identifier for the mangled name of a this-adjusting or
+ covariant thunk to FN_DECL. FIXED_OFFSET is the initial adjustment
+ to this used to find the vptr. If VIRTUAL_OFFSET is non-NULL, this
+ is a virtual thunk, and it is the vtbl offset in
+ bytes. THIS_ADJUSTING is nonzero for a this adjusting thunk and
+ zero for a covariant thunk. Note, that FN_DECL might be a covariant
+ thunk itself. A covariant thunk name always includes the adjustment
+ for the this pointer, even if there is none.
+
+ <special-name> ::= T <call-offset> <base encoding>
+ ::= Tc <this_adjust call-offset> <result_adjust call-offset>
+ <base encoding> */
+
+tree
+mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
+ tree virtual_offset)
+{
+ const char *result;
+
+ start_mangling (fn_decl, /*ident_p=*/true);
+
+ write_string ("_Z");
+ write_char ('T');
+
+ if (!this_adjusting)
+ {
+ /* Covariant thunk with no this adjustment */
+ write_char ('c');
+ mangle_call_offset (integer_zero_node, NULL_TREE);
+ mangle_call_offset (fixed_offset, virtual_offset);
+ }
+ else if (!DECL_THUNK_P (fn_decl))
+ /* Plain this adjusting thunk. */
+ mangle_call_offset (fixed_offset, virtual_offset);
+ else
+ {
+ /* This adjusting thunk to covariant thunk. */
+ write_char ('c');
+ mangle_call_offset (fixed_offset, virtual_offset);
+ fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn_decl));
+ virtual_offset = THUNK_VIRTUAL_OFFSET (fn_decl);
+ if (virtual_offset)
+ virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+ mangle_call_offset (fixed_offset, virtual_offset);
+ fn_decl = THUNK_TARGET (fn_decl);
+ }
+
+ /* Scoped name. */
+ write_encoding (fn_decl);
+
+ result = finish_mangling (/*warn=*/false);
+ if (DEBUG_MANGLE)
+ fprintf (stderr, "mangle_thunk = %s\n\n", result);
+ return get_identifier_nocopy (result);
+}
+
+/* This hash table maps TYPEs to the IDENTIFIER for a conversion
+ 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;
+
+/* Hash a node (VAL1) in the table. */
+
+static hashval_t
+hash_type (const void *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_TYPE ((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;
+
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ 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,
+ (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;
+ }
+
+ return identifier;
+}
+
+/* Return an identifier for the name of an initialization guard
+ variable for indicated VARIABLE. */
+
+tree
+mangle_guard_variable (const tree 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
+ to the reference, not the temporary. */
+ write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
+ else
+ write_name (variable, /*ignore_local_scope=*/0);
+ return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+}
+
+/* Return an identifier for the name of a temporary variable used to
+ initialize a static reference. This isn't part of the ABI, but we might
+ as well call them something readable. */
+
+tree
+mangle_ref_init_variable (const tree variable)
+{
+ start_mangling (variable, /*ident_p=*/true);
+ write_string ("_ZGR");
+ write_name (variable, /*ignore_local_scope=*/0);
+ return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+}
+
+
+/* Foreign language type mangling section. */
+
+/* How to write the type codes for the integer Java type. */
+
+static void
+write_java_integer_type_codes (const tree type)
+{
+ if (type == java_int_type_node)
+ write_char ('i');
+ else if (type == java_short_type_node)
+ write_char ('s');
+ else if (type == java_byte_type_node)
+ write_char ('c');
+ else if (type == java_char_type_node)
+ write_char ('w');
+ else if (type == java_long_type_node)
+ write_char ('x');
+ else if (type == java_boolean_type_node)
+ write_char ('b');
+ else
+ gcc_unreachable ();
+}
+
+#include "gt-cp-mangle.h"