-/* Name mangling for the new standard C++ ABI.
- Copyright (C) 2000 Free Software Foundation, Inc.
+/* Name mangling for the 3.0 C++ ABI.
+ Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Written by Alex Samuel <sameul@codesourcery.com>
- This file is part of GNU CC.
+ This file is part of GCC.
- GNU CC is free software; you can redistribute it and/or modify it
+ 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.
- GNU CC is distributed in the hope that it will be useful, but
+ 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 GNU CC; see the file COPYING. If not, write to the Free
+ along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
+#include "real.h"
#include "obstack.h"
#include "toplev.h"
#include "varray.h"
/* Macros for tracing the write_* functions. */
#if DEBUG_MANGLE
# define MANGLE_TRACE(FN, INPUT) \
- fprintf (stderr, " %-24s: %-24s\n", 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)
+ (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
#else
# define MANGLE_TRACE(FN, INPUT)
# define MANGLE_TRACE_TREE(FN, NODE)
#endif
-/* Non-zero if NODE is a template-id. */
-#define DECL_TEMPLATE_ID_P(NODE) \
- (DECL_LANG_SPECIFIC (NODE) != NULL \
- && DECL_USE_TEMPLATE (NODE) \
- && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (NODE)))
-
-/* Non-zero if NODE is a class template-id. */
-#define CLASSTYPE_TEMPLATE_ID_P(NODE) \
- (TYPE_LANG_SPECIFIC (NODE) != NULL \
- && CLASSTYPE_USE_TEMPLATE (NODE) \
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
+/* 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. */
static struct globals
/* The name in which we're building the mangled name. */
struct obstack name_obstack;
- /* The current innermost template args. */
- tree template_args;
-
/* 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;
+
+ /* We are mangling an internal symbol. It is important to keep those
+ involving template parmeters distinct by distinguishing their level
+ and, for non-type parms, their type. */
+ bool internal_mangling_p;
+
+ /* True if the mangling will be different in a future version of the
+ ABI. */
+ bool need_abi_warning;
} G;
/* Indices into subst_identifiers. These are identifiers used in
/* Single-letter codes for builtin integer types, defined in
<builtin-type>. These are indexed by integer_type_kind values. */
-static char
+static const char
integer_type_codes[itk_none] =
{
'c', /* itk_char */
'y' /* itk_unsigned_long_long */
};
+static int decl_is_template_id PARAMS ((tree, tree*));
+
/* Functions for handling substitutions. */
static inline tree canonicalize_for_substitution PARAMS ((tree));
static inline int is_std_substitution PARAMS ((tree, substitution_identifier_index_t));
static inline int is_std_substitution_char PARAMS ((tree, substitution_identifier_index_t));
static int find_substitution PARAMS ((tree));
+static void mangle_call_offset PARAMS ((tree, tree));
/* Functions for emitting mangled representations of things. */
static void write_mangled_name PARAMS ((tree));
static void write_encoding PARAMS ((tree));
-static void write_name PARAMS ((tree));
+static void write_name PARAMS ((tree, int));
static void write_unscoped_name PARAMS ((tree));
static void write_unscoped_template_name PARAMS ((tree));
static void write_nested_name PARAMS ((tree));
static void write_prefix PARAMS ((tree));
static void write_template_prefix PARAMS ((tree));
-static void write_component PARAMS ((tree));
static void write_unqualified_name PARAMS ((tree));
+static void write_conversion_operator_name (tree);
static void write_source_name PARAMS ((tree));
+static int hwint_to_ascii PARAMS ((unsigned HOST_WIDE_INT, unsigned int, char *, unsigned));
static void write_number PARAMS ((unsigned HOST_WIDE_INT, int,
unsigned int));
static void write_integer_cst PARAMS ((tree));
-static void write_identifier PARAMS ((char *));
+static void write_identifier PARAMS ((const char *));
static void write_special_name_constructor PARAMS ((tree));
static void write_special_name_destructor PARAMS ((tree));
static void write_type PARAMS ((tree));
static int write_CV_qualifiers_for_type PARAMS ((tree));
static void write_builtin_type PARAMS ((tree));
-static void write_function_type PARAMS ((tree, int));
-static void write_bare_function_type PARAMS ((tree, int));
-static void write_method_parms PARAMS ((tree, int));
+static void write_function_type PARAMS ((tree));
+static void write_bare_function_type PARAMS ((tree, int, tree));
+static void write_method_parms PARAMS ((tree, int, tree));
static void write_class_enum_type PARAMS ((tree));
static void write_template_args PARAMS ((tree));
static void write_expression PARAMS ((tree));
static int discriminator_for_local_entity PARAMS ((tree));
static int discriminator_for_string_literal PARAMS ((tree, tree));
static void write_discriminator PARAMS ((int));
-static void write_local_name PARAMS ((tree, tree));
+static void write_local_name PARAMS ((tree, tree, tree));
static void dump_substitution_candidates PARAMS ((void));
static const char *mangle_decl_string PARAMS ((tree));
/* Control functions. */
-static inline void start_mangling PARAMS ((void));
-static inline const char *finish_mangling PARAMS ((void));
+static inline void start_mangling (tree);
+static inline const char *finish_mangling (bool);
static tree mangle_special_for_type PARAMS ((tree, const char *));
+/* Foreign language functions. */
+
+static void write_java_integer_type_codes PARAMS ((tree));
+
/* Append a single character to the end of the mangled
representation. */
#define write_char(CHAR) \
obstack_1grow (&G.name_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))
+
/* Append a NUL-terminated string to the end of the mangled
representation. */
#define write_string(STRING) \
obstack_grow (&G.name_obstack, (STRING), strlen (STRING))
-/* Return the position at which the next character will be appended to
- the mangled representation. */
-#define mangled_position() \
- obstack_object_size (&G.name_obstack)
-
-/* Non-zero if NODE1 and NODE2 are both TREE_LIST nodes and have the
+/* 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. */
|| TREE_PURPOSE (NODE1) == TREE_PURPOSE (NODE2)) \
&& TREE_VALUE (NODE1) == TREE_VALUE (NODE2))
-/* Write out a signed quantity in base 10. */
-#define write_signed_number(NUMBER) \
- write_number (NUMBER, /*unsigned_p=*/0, 10)
-
/* Write out an unsigned quantity in base 10. */
#define write_unsigned_number(NUMBER) \
- write_number (NUMBER, /*unsigned_p=*/1, 10)
+ write_number ((NUMBER), /*unsigned_p=*/1, 10)
+
+/* 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 (decl, template_info)
+ tree decl;
+ tree* 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. */
+ 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. */
/* 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;
}
|| (TYPE_P (node)
&& TYPE_P (candidate)
&& same_type_p (node, candidate)))
- my_friendly_abort (20000524);
+ abort ();
}
}
#endif /* ENABLE_CHECKING */
dump_substitution_candidates ();
}
-/* Helper function for find_substitution. Returns non-zero if NODE,
+/* 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. */
return (DECL_NAMESPACE_STD_P (CP_DECL_CONTEXT (decl))
&& TYPE_LANG_SPECIFIC (type)
- && CLASSTYPE_TEMPLATE_INFO (type)
- && (DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))
+ && TYPE_TEMPLATE_INFO (type)
+ && (DECL_NAME (TYPE_TI_TEMPLATE (type))
== subst_identifiers[index]));
}
-/* Helper function for find_substitution. Returns non-zero if NODE,
+/* 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]. */
candidates for entities appearing earlier in the same mangling
If a substitution is found, write its mangled representation and
- return non-zero. If none is found, just return zero. */
+ return nonzero. If none is found, just return zero. */
static int
find_substitution (node)
std::basic_string <char,
std::char_traits<char>,
std::allocator<char> > . */
- if (CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+ if (cp_type_quals (type) == TYPE_UNQUALIFIED
&& CLASSTYPE_USE_TEMPLATE (type))
{
tree args = CLASSTYPE_TI_ARGS (type);
/* Check for basic_{i,o,io}stream. */
if (TYPE_P (node)
- && CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+ && cp_type_quals (type) == TYPE_UNQUALIFIED
&& CLASS_TYPE_P (type)
&& CLASSTYPE_USE_TEMPLATE (type)
&& CLASSTYPE_TEMPLATE_INFO (type) != NULL)
}
/* Now check the list of available substitutions for this mangling
- operation. */
+ operation. */
for (i = 0; i < size; ++i)
{
tree candidate = VARRAY_TREE (G.substitutions, i);
{
MANGLE_TRACE_TREE ("mangled-name", decl);
- if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (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." */
+ 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));
else
/* C++ name; needs to be mangled. */
if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl))
{
- write_source_name (DECL_NAME (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);
+ write_name (decl, /*ignore_local_scope=*/0);
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree fn_type;
- if (DECL_TEMPLATE_ID_P (decl))
- fn_type = get_mostly_instantiated_function_type (decl, NULL, NULL);
+ if (decl_is_template_id (decl, NULL))
+ fn_type = get_mostly_instantiated_function_type (decl);
else
fn_type = TREE_TYPE (decl);
- write_bare_function_type (fn_type, DECL_TEMPLATE_ID_P (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);
}
}
/* <name> ::= <unscoped-name>
::= <unscoped-template-name> <template-args>
::= <nested-name>
- ::= <local-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 (decl)
+write_name (decl, ignore_local_scope)
tree decl;
+ int ignore_local_scope;
{
tree context;
- context = CP_DECL_CONTEXT (decl);
-
MANGLE_TRACE_TREE ("name", decl);
- /* Decls in :: or ::std scope are treated specially. */
- if (context == global_namespace || DECL_NAMESPACE_STD_P (context))
+ if (TREE_CODE (decl) == TYPE_DECL)
{
- if (decl && DECL_TEMPLATE_ID_P (decl))
- {
- /* Templated decls get an <unqualified-template-name>. */
- write_unscoped_template_name (DECL_TI_TEMPLATE (decl));
- write_template_args (DECL_TI_ARGS (decl));
- }
- else if (TREE_CODE (decl) == TYPE_DECL
- && CLASSTYPE_TEMPLATE_ID_P (TREE_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))
{
- tree type;
-
- /* Templated decls get an <unqualified-template-name>. */
- type = TREE_TYPE (decl);
- write_unscoped_template_name (TYPE_TI_TEMPLATE (type));
- write_template_args (TYPE_TI_ARGS (type));
+ /* 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);
}
- /* Handle local names. */
- else if (TREE_CODE (context) == FUNCTION_DECL)
- write_local_name (context, decl);
- /* Other decls get a <nested-name> to encode their scope. */
else
- write_nested_name (decl);
+ {
+ /* 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>
write_string ("St");
write_unqualified_name (decl);
}
- /* If not, it should be in the global namespace. */
- else if (context == global_namespace || context == NULL)
+ /* 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
- my_friendly_abort (20000521);
+ abort ();
}
/* <unscoped-template-name> ::= <unscoped-name>
/* Write the nested name, including CV-qualifiers, of DECL.
- <nested-name> ::= N [<CV-qualifiers>] <prefix> <component> E
+ <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
::= N [<CV-qualifiers>] <template-prefix> <template-args> E
<CV-qualifiers> ::= [r] [V] [K] */
write_nested_name (decl)
tree decl;
{
+ tree template_info;
+
MANGLE_TRACE_TREE ("nested-name", decl);
write_char ('N');
write_char ('K');
}
- if (DECL_TEMPLATE_ID_P (decl))
- {
- write_template_prefix (decl);
- write_template_args (DECL_TI_ARGS (decl));
- }
- else if (CLASSTYPE_TEMPLATE_ID_P (TREE_TYPE (decl)))
+ /* Is this a template instance? */
+ if (decl_is_template_id (decl, &template_info))
{
+ /* Yes, use <template-prefix>. */
write_template_prefix (decl);
- write_template_args (CLASSTYPE_TI_ARGS (TREE_TYPE (decl)));
+ write_template_args (TI_ARGS (template_info));
}
else
{
+ /* No, just use <prefix> */
write_prefix (DECL_CONTEXT (decl));
- write_component (decl);
+ write_unqualified_name (decl);
}
write_char ('E');
}
-/* <prefix> ::= <prefix> <component>
+/* <prefix> ::= <prefix> <unqualified-name>
+ ::= <template-param>
::= <template-prefix> <template-args>
::= # empty
::= <substitution> */
tree node;
{
tree decl;
- tree type;
- tree context;
+ /* Non-NULL if NODE represents a template-id. */
+ tree template_info = NULL;
+
+ MANGLE_TRACE_TREE ("prefix", node);
if (node == NULL
|| node == global_namespace)
return;
- MANGLE_TRACE_TREE ("prefix", node);
-
- decl = DECL_P (node) ? node : TYPE_NAME (node);
- type = DECL_P (node) ? TREE_TYPE (node) : node;
- context = CP_DECL_CONTEXT (decl);
-
if (find_substitution (node))
return;
- /* Check if this is a template-id. For a template member, the
- template info will be hanging off the decl. */
- if (DECL_TEMPLATE_ID_P (decl))
+ if (DECL_P (node))
{
- write_template_prefix (decl);
- write_template_args (DECL_TI_ARGS (decl));
+ /* 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);
}
- /* For a template class, the template info will be hanging off the
- type. */
- else if (type && CLASSTYPE_TEMPLATE_ID_P (type))
+ else
{
- write_template_prefix (type);
- write_template_args (CLASSTYPE_TI_ARGS (type));
+ /* 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 (context);
- write_component (decl);
+ write_prefix (CP_DECL_CONTEXT (decl));
+ write_unqualified_name (decl);
}
add_substitution (node);
}
/* <template-prefix> ::= <prefix> <template component>
+ ::= <template-param>
::= <substitution> */
static void
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_TEMPLATE_ID_P (decl))
- template = DECL_TI_TEMPLATE (decl);
+ if (decl_is_template_id (decl, &template_info))
+ template = TI_TEMPLATE (template_info);
else if (CLASSTYPE_TEMPLATE_ID_P (type))
- template = CLASSTYPE_TI_TEMPLATE (type);
+ template = TYPE_TI_TEMPLATE (type);
else
/* Oops, not a template. */
- my_friendly_abort (20000524);
+ abort ();
/* For a member template, though, the template name for the
innermost name must have all the outer template levels
if (find_substitution (substitution))
return;
- write_prefix (context);
- write_component (decl);
-
- add_substitution (substitution);
-}
-
-/* <component> ::= <unqualified-name>
- ::= <local-name> */
+ /* 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;
-static void
-write_component (decl)
- tree decl;
-{
- MANGLE_TRACE_TREE ("component", decl);
-
- switch (TREE_CODE (decl))
+ if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+ && abi_version_at_least (2))
+ write_template_param (TREE_TYPE (template));
+ else
{
- case TEMPLATE_DECL:
- case NAMESPACE_DECL:
- case VAR_DECL:
- case TYPE_DECL:
- case FUNCTION_DECL:
- case FIELD_DECL:
- if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
- write_local_name (CP_DECL_CONTEXT (decl), decl);
- else
- write_unqualified_name (decl);
- break;
-
- default:
- my_friendly_abort (2000509);
+ write_prefix (context);
+ write_unqualified_name (decl);
}
+
+ add_substitution (substitution);
}
/* We don't need to handle thunks, vtables, or VTTs here. Those are
{
/* Conversion operator. Handle it right here.
<operator> ::= cv <type> */
- write_string ("cv");
- write_type (TREE_TYPE (DECL_NAME (decl)));
+ tree type;
+ if (decl_is_template_id (decl, NULL))
+ {
+ tree fn_type = get_mostly_instantiated_function_type (decl);
+ type = TREE_TYPE (fn_type);
+ }
+ else
+ type = TREE_TYPE (DECL_NAME (decl));
+ write_conversion_operator_name (type);
}
else if (DECL_OVERLOADED_OPERATOR_P (decl))
{
write_source_name (DECL_NAME (decl));
}
+/* Write the unqualified-name for a conversion operator to TYPE. */
+
+static void
+write_conversion_operator_name (tree type)
+{
+ write_string ("cv");
+ write_type (type);
+}
+
/* Non-termial <source-name>. IDENTIFIER is an IDENTIFIER_NODE.
<source-name> ::= </length/ number> <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 (number, base, buffer, min_digits)
+ unsigned HOST_WIDE_INT number;
+ unsigned int base;
+ char *buffer;
+ unsigned 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/> */
int unsigned_p;
unsigned int base;
{
- static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- unsigned HOST_WIDE_INT n;
- unsigned HOST_WIDE_INT m = 1;
+ 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);
}
-
- /* Figure out how many digits there are. */
- n = number;
- while (n >= base)
- {
- n /= base;
- m *= base;
- }
-
- /* Write them out. */
- while (m > 0)
- {
- int digit = number / m;
- write_char (digits[digit]);
- number -= digit * m;
- m /= base;
- }
-
- my_friendly_assert (number == 0, 20000407);
+ count = hwint_to_ascii (number, base, buffer + sizeof (buffer), 1);
+ write_chars (buffer + sizeof (buffer) - count, count);
}
-/* Write out an integeral CST in decimal. */
+/* 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 (cst)
tree cst;
{
- if (tree_int_cst_sgn (cst) >= 0)
+ int sign = tree_int_cst_sgn (cst);
+
+ if (TREE_INT_CST_HIGH (cst) + (sign < 0))
{
- if (TREE_INT_CST_HIGH (cst) != 0)
- sorry ("mangling very large integers");
- write_unsigned_number (TREE_INT_CST_LOW (cst));
+ /* 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_2 (chunk, 0);
+ n = build_int_2 (TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
+ TREE_TYPE (n) = TREE_TYPE (base) = type;
+
+ if (sign < 0)
+ {
+ write_char ('n');
+ n = fold (build1 (NEGATE_EXPR, type, n));
+ }
+ do
+ {
+ tree d = fold (build (FLOOR_DIV_EXPR, type, n, base));
+ tree tmp = fold (build (MULT_EXPR, type, d, base));
+ unsigned c;
+
+ done = integer_zerop (d);
+ tmp = fold (build (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);
}
- else
- write_signed_number (tree_low_cst (cst, 0));
}
/* Non-terminal <identifier>.
static void
write_identifier (identifier)
- char *identifier;
+ const char *identifier;
{
MANGLE_TRACE ("identifier", identifier);
write_string (identifier);
<special-name> ::= C1 # complete object constructor
::= C2 # base object constructor
::= C3 # complete object allocating constructor
- ::= C4 # base object allocating constructor
Currently, allocating constructors are never used.
- We also need to provide unique mangled names (which should never be
- exported) for the constructor that takes an in-charge parameter,
- and for a constructor whose name is the same as its class's name.
- We use "C*INTERNAL*" for these. */
+ We also need to provide mangled names for the maybe-in-charge
+ constructor, 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_constructor (ctor)
tree ctor;
{
- if (DECL_COMPLETE_CONSTRUCTOR_P (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))
write_string ("C2");
else
- write_string ("C*INTERNAL*");
+ abort ();
}
/* Handle destructor productions of non-terminal <special-name>.
- DTOR is a denstructor FUNCTION_DECL.
+ 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
+ ::= D2 # base object (not-in-charge) destructor
- We also need to provide unique mngled names for old-ABI
- destructors, sometimes. These should only be used internally. We
- use "D*INTERNAL*" for these. */
+ 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 (dtor)
{
if (DECL_DELETING_DESTRUCTOR_P (dtor))
write_string ("D0");
- else if (DECL_COMPLETE_DESTRUCTOR_P (dtor))
+ 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
- /* Old-ABI destructor. */
- write_string ("D*INTERNAL*");
+ abort ();
}
/* Return the discriminator for ENTITY appearing inside
/* Assume this is the only local entity with this name. */
discriminator = 0;
- /* For now, we don't discriminate amongst local variables. */
- if (TREE_CODE (entity) != TYPE_DECL)
- return 0;
-
- /* Scan the list of local classes. */
- entity = TREE_TYPE (entity);
- for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
- if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
- && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
- ++discriminator;
+ if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
+ discriminator = DECL_DISCRIMINATOR (entity);
+ else if (TREE_CODE (entity) == TYPE_DECL)
+ {
+ /* Scan the list of local classes. */
+ entity = TREE_TYPE (entity);
+ for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
+ if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
+ && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
+ ++discriminator;
+ }
return discriminator;
}
write_discriminator (discriminator)
int discriminator;
{
- /* If discriminator is zero, don't write anything. Otherwise... */
+ /* If discriminator is zero, don't write anything. Otherwise... */
if (discriminator > 0)
{
write_char ('_');
- /* The number is omitted for discriminator == 1. Beyond 1, the
- numbering starts at 0. */
- if (discriminator > 1)
- write_unsigned_number (discriminator - 2);
+ 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.
+ 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 (function, entity)
+write_local_name (function, local_entity, entity)
tree function;
+ tree local_entity;
tree entity;
{
MANGLE_TRACE_TREE ("local-name", entity);
}
else
{
- write_unqualified_name (entity);
- write_discriminator (discriminator_for_local_entity (entity));
+ /* 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));
}
}
::= <CV-qualifier>
::= P <type> # pointer-to
::= R <type> # reference-to
- ::= C <type> # complex pair (C 2000) [not supported]
+ ::= C <type> # complex pair (C 2000)
::= G <type> # imaginary (C 2000) [not supported]
::= U <source-name> <type> # vendor extended type qualifier
- [not supported]
TYPE is a type node. */
write_type (type)
tree type;
{
- /* This gets set to non-zero if TYPE turns out to be a (possibly
+ /* 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;
since both the qualified and uqualified 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
{
/* See through any typedefs. */
case FUNCTION_TYPE:
case METHOD_TYPE:
- write_function_type (type, 1);
+ write_function_type (type);
break;
case UNION_TYPE:
break;
case TYPENAME_TYPE:
- /* We handle TYPENAME_TYPEs like ordinary nested names. */
+ 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 ARRAY_TYPE:
- write_array_type (type);
- break;
-
case POINTER_TYPE:
/* A pointer-to-member variable is represented by a POINTER_TYPE
to an OFFSET_TYPE, so check for this first. */
case TEMPLATE_TEMPLATE_PARM:
write_template_template_param (type);
- if (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type))
- write_template_args
- (TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (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 OFFSET_TYPE:
write_pointer_to_member_type (build_pointer_type (type));
break;
+ case VECTOR_TYPE:
+ write_string ("U8__vector");
+ write_type (TREE_TYPE (type));
+ break;
+
default:
- my_friendly_abort (20000409);
+ abort ();
}
}
"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) ..." */
+ 'V', 'r', and 'U' (farthest from the base type) ..."
- if (CP_TYPE_RESTRICT_P (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 (CP_TYPE_VOLATILE_P (type))
+ if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
{
write_char ('V');
++num_qualifiers;
}
- if (CP_TYPE_CONST_P (type))
+ if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
{
write_char ('K');
++num_qualifiers;
::= m # unsigned long
::= x # long long, __int64
::= y # unsigned long long, __int64
- ::= n # __int128 [not supported]
- ::= o # unsigned __int128 [not supported]
+ ::= n # __int128
+ ::= o # unsigned __int128
::= f # float
::= d # double
::= e # long double, __float80
- ::= g # __float128 [not supported] */
+ ::= g # __float128 [not supported]
+ ::= u <source-name> # vendor extended type */
static void
write_builtin_type (type)
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])
{
write_char (integer_type_codes[itk]);
break;
}
-
+
if (itk == itk_none)
- /* Couldn't find this type. */
- my_friendly_abort (20000408);
+ {
+ tree t = c_common_type_for_mode (TYPE_MODE (type),
+ TREE_UNSIGNED (type));
+ if (type == t)
+ {
+ if (TYPE_PRECISION (type) == 128)
+ write_char (TREE_UNSIGNED (type) ? 'o' : 'n');
+ else
+ /* Couldn't find this type. */
+ abort ();
+ }
+ else
+ {
+ type = t;
+ goto iagain;
+ }
+ }
}
break;
case REAL_TYPE:
- if (type == float_type_node)
+ if (type == float_type_node
+ || type == java_float_type_node)
write_char ('f');
- else if (type == double_type_node)
+ 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
- my_friendly_abort (20000409);
+ abort ();
break;
default:
- my_friendly_abort (20000509);
+ abort ();
}
}
/* Non-terminal <function-type>. NODE is a FUNCTION_TYPE or
- METHOD_TYPE. If INCLUDE_RETURN_TYPE is non-zero, the return type
- is mangled before the parameter types.
+ METHOD_TYPE. The return type is mangled before the parameter
+ types.
<function-type> ::= F [Y] <bare-function-type> E */
static void
-write_function_type (type, include_return_type)
+write_function_type (type)
tree type;
- int include_return_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" function_t f; // Vice versa.
See [dcl.link]. */
- write_bare_function_type (type, include_return_type);
+ write_bare_function_type (type, /*include_return_type_p=*/1,
+ /*decl=*/NULL);
write_char ('E');
}
-/* Non-terminal <bare-function-type>. NODE is a FUNCTION_DECL or a
- METHOD_TYPE. If INCLUDE_RETURN_TYPE is non-zero, the return value
- is mangled before the parameter types.
+/* 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.
<bare-function-type> ::= </signature/ type>+ */
static void
-write_bare_function_type (type, include_return_type_p)
+write_bare_function_type (type, include_return_type_p, decl)
tree type;
int include_return_type_p;
+ tree decl;
{
MANGLE_TRACE_TREE ("bare-function-type", type);
/* Now mangle the types of the arguments. */
write_method_parms (TYPE_ARG_TYPES (type),
- TREE_CODE (type) == METHOD_TYPE);
+ TREE_CODE (type) == METHOD_TYPE,
+ decl);
}
/* Write the mangled representation of a method parameter list of
- types given in PARM_LIST. If METHOD_P is non-zero, the function is
+ 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 VARARGS_P is non-zero, an additional token designating varargs
- is appended. */
+ If non-NULL, DECL is the FUNCTION_DECL for the function whose
+ parameters are being emitted. */
static void
-write_method_parms (parm_list, method_p)
- tree parm_list;
+write_method_parms (parm_types, method_p, decl)
+ tree decl;
+ tree parm_types;
int method_p;
{
- tree first_parm;
+ 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." */
+ parameter."
+
+ Similarly, there's no need to mangle artificial parameters, like
+ the VTT parameters for constructors and destructors. */
if (method_p)
- parm_list = TREE_CHAIN (parm_list);
-
- for (first_parm = parm_list;
- parm_list;
- parm_list = TREE_CHAIN (parm_list))
{
- tree parm = TREE_VALUE (parm_list);
+ 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_list == first_parm)
+ 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. */
- my_friendly_assert (TREE_CHAIN (parm_list) == NULL, 20000523);
+ my_friendly_assert (TREE_CHAIN (parm_types) == NULL, 20000523);
}
else
write_type (parm);
write_class_enum_type (type)
tree type;
{
- write_name (TYPE_NAME (type));
+ write_name (TYPE_NAME (type), /*ignore_local_scope=*/0);
}
/* Non-terminal <template-args>. ARGS is a TREE_VEC of template
write_template_args (args)
tree args;
{
- int i;
- int length = TREE_VEC_LENGTH (args);
-
MANGLE_TRACE_TREE ("template-args", args);
- my_friendly_assert (length > 0, 20000422);
+ write_char ('I');
- if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ if (TREE_CODE (args) == TREE_VEC)
+ {
+ int i;
+ int length = TREE_VEC_LENGTH (args);
+ my_friendly_assert (length > 0, 20000422);
+
+ 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
{
- /* We have nested template args. We want the innermost template
- argument list. */
- args = TREE_VEC_ELT (args, length - 1);
- length = TREE_VEC_LENGTH (args);
+ my_friendly_assert (TREE_CODE (args) == TREE_LIST, 20021014);
+
+ while (args)
+ {
+ write_template_arg (TREE_VALUE (args));
+ args = TREE_CHAIN (args);
+ }
}
- write_char ('I');
- for (i = 0; i < length; ++i)
- write_template_arg (TREE_VEC_ELT (args, i));
write_char ('E');
}
<expr-primary> ::= <template-param>
::= L <type> <value number> E # literal
- ::= L <mangled-name> E # external name */
+ ::= L <mangled-name> E # external name
+ ::= sr <type> <unqualified-name>
+ ::= sr <type> <unqualified-name> <template-args> */
static void
write_expression (expr)
code = TREE_CODE (expr);
}
- /* Handle template parameters. */
+ /* 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)
+ || code == BOUND_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) == 'c'
+ || (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);
write_char ('E');
}
- else
+ else if (TREE_CODE (expr) == SIZEOF_EXPR
+ && TYPE_P (TREE_OPERAND (expr, 0)))
{
- int i;
-
- /* 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)
+ 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
{
- expr = TREE_OPERAND (expr, 0);
- code = TREE_CODE (expr);
+ 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);
+ if (TREE_CODE (member) == LOOKUP_EXPR)
+ 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
code = TREE_CODE (expr);
}
-
+
/* If it wasn't any of those, recursively expand the expression. */
write_string (operator_name_info[(int) code].mangled_name);
- /* Handle pointers-to-members specially. */
- if (code == SCOPE_REF)
+ switch (code)
{
+ case CAST_EXPR:
+ write_type (TREE_TYPE (expr));
+ 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
- write_encoding (TREE_OPERAND (expr, 1));
+ {
+ /* 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)
+ write_expression (TREE_OPERAND (expr, i));
}
- else
- for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
- write_expression (TREE_OPERAND (expr, i));
}
}
else if (value == boolean_true_node)
write_unsigned_number (1);
else
- my_friendly_abort (20000412);
+ abort ();
}
else
write_integer_cst (value);
#endif
}
else
- my_friendly_abort (20000412);
+ abort ();
write_char ('E');
}
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)
+ || (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)
+ G.need_abi_warning = 1;
write_char ('L');
write_char ('Z');
write_encoding (node);
write_char ('E');
}
- else if (TREE_CODE_CLASS (code) == 'c' && code != PTRMEM_CST)
- write_template_arg_literal (node);
else
{
/* Template arguments may be expressions. */
if (find_substitution (decl))
return;
- write_name (decl);
+ 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
}
/* Non-terminal <template-param>. PARM is a TEMPLATE_TYPE_PARM,
- TEMPLATE_TEMPLATE_PARM, or a TEMPLATE_PARM_INDEX.
+ TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
+ TEMPLATE_PARM_INDEX.
- <template-param> ::= T </parameter/ number> _ */
+ <template-param> ::= T </parameter/ number> _
+
+ If we are internally mangling then we distinguish level and, for
+ non-type parms, type too. The mangling appends
+
+ </level/ number> _ </non-type type/ type> _
+
+ This is used by mangle_conv_op_name_for_type. */
static void
write_template_param (parm)
tree parm;
{
int parm_index;
+ int parm_level;
+ tree parm_type = NULL_TREE;
MANGLE_TRACE_TREE ("template-parm", 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:
- my_friendly_abort (20000523);
+ abort ();
}
write_char ('T');
if (parm_index > 0)
write_unsigned_number (parm_index - 1);
write_char ('_');
+ if (G.internal_mangling_p)
+ {
+ if (parm_level > 0)
+ write_unsigned_number (parm_level - 1);
+ write_char ('_');
+ if (parm_type)
+ write_type (parm_type);
+ write_char ('_');
+ }
}
/* <template-template-param>
/* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
template template parameter. The substitution candidate here is
only the template. */
- if (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm))
+ if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
template
= TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
write_char ('_');
}
-/* Start mangling a new name or type. */
+/* Start mangling ENTITY. */
static inline void
-start_mangling ()
+start_mangling (tree entity)
{
+ 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));
}
-/* Done with mangling. Return the generated mangled name. */
+/* 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 ()
+finish_mangling (bool warn)
{
+ if (warn_abi && warn && G.need_abi_warning)
+ warning ("the mangled name of `%D' will change in a future "
+ "version of GCC",
+ G.entity);
+
/* Clear all the substitutions. */
- VARRAY_POP_ALL (G.substitutions);
+ G.substitutions = 0;
/* Null-terminate the string. */
write_char ('\0');
init_mangle ()
{
gcc_obstack_init (&G.name_obstack);
- VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
/* Cache these identifiers for quick comparison when checking for
standard substitutions. */
{
const char *result;
- start_mangling ();
+ start_mangling (decl);
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);
+ {
+ 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* ");
+ }
- result = finish_mangling ();
+ result = finish_mangling (/*warn=*/true);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
return result;
/* Create an identifier for the external mangled name of DECL. */
-tree
+void
mangle_decl (decl)
tree decl;
{
- return get_identifier (mangle_decl_string (decl));
+ tree id = get_identifier (mangle_decl_string (decl));
+
+ SET_DECL_ASSEMBLER_NAME (decl, id);
}
/* Generate the mangled representation of TYPE. */
{
const char *result;
- start_mangling ();
+ start_mangling (type);
write_type (type);
- result = finish_mangling ();
+ result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
return 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 ();
+ start_mangling (type);
/* Start the mangling. */
write_string ("_Z");
/* Add the type. */
write_type (type);
- result = finish_mangling ();
+ result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
{
const char *result;
- start_mangling ();
+ start_mangling (type);
write_string ("_Z");
write_string ("TC");
write_char ('_');
write_type (BINFO_TYPE (binfo));
- result = finish_mangling ();
+ result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
return get_identifier (result);
}
-/* Return an identifier for the mangled name of a thunk to FN_DECL.
- OFFSET is the initial adjustment to this used to find the vptr. If
- VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
- vtbl offset in bytes.
+/* 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 (fixed_offset, virtual_offset)
+ tree fixed_offset;
+ tree virtual_offset;
+{
+ write_char (virtual_offset ? 'v' : 'h');
+
+ /* For either flavor, write the fixed offset. */
+ write_integer_cst (fixed_offset);
+ write_char ('_');
- <special-name> ::= Th <offset number> _ <base encoding>
- ::= Tv <offset number> _ <vcall offset number> _
- <base encoding>
+ /* 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 non-zero 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 (fn_decl, offset, vcall_offset)
+mangle_thunk (fn_decl, this_adjusting, fixed_offset, virtual_offset)
tree fn_decl;
- tree offset;
- tree vcall_offset;
+ int this_adjusting;
+ tree fixed_offset;
+ tree virtual_offset;
{
const char *result;
- start_mangling ();
+ start_mangling (fn_decl);
write_string ("_Z");
- /* The <special-name> for virtual thunks is Tv, for non-virtual
- thunks Th. */
write_char ('T');
- if (vcall_offset != 0)
- write_char ('v');
+
+ 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
- write_char ('h');
-
- /* For either flavor, write the offset to this. */
- write_integer_cst (offset);
- write_char ('_');
-
- /* For a virtual thunk, add the vcall offset. */
- if (vcall_offset)
{
- /* Virtual thunk. Write the vcall offset and base type name. */
- write_integer_cst (vcall_offset);
- write_char ('_');
+ /* 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 ();
+ result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", result);
return get_identifier (result);
/* 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.
-
- For compatibility with existing conversion operator mechanisms,
- the mangled form is `__op<type>' where <type> is the mangled
- representation of TYPE.
-
- FIXME: Though identifiers with starting with __op are reserved for
- the implementation, it would eventually be nice to use inaccessible
- names for these operators. */
+ ABI spec; it is only used internally. */
tree
mangle_conv_op_name_for_type (type)
tree type;
{
tree identifier;
+ const char *mangled_type;
+ char *op_name;
- /* Build the mangling for TYPE. */
- const char *mangled_type = mangle_type_string (type);
+ /* Build the internal mangling for TYPE. */
+ G.internal_mangling_p = true;
+ mangled_type = mangle_type_string (type);
+ G.internal_mangling_p = false;
+
/* Allocate a temporary buffer for the complete name. */
- char *op_name = (char *) xmalloc (strlen (OPERATOR_TYPENAME_FORMAT)
- + strlen (mangled_type) + 1);
- /* Assemble the mangling. */
- strcpy (op_name, OPERATOR_TYPENAME_FORMAT);
- strcat (op_name, mangled_type);
+ op_name = concat ("operator ", mangled_type, NULL);
/* Find or create an identifier. */
identifier = get_identifier (op_name);
/* Done with the temporary buffer. */
free (op_name);
+
+ /* It had better be a unique mangling for the type. */
+ if (IDENTIFIER_TYPENAME_P (identifier)
+ && !same_type_p (type, TREE_TYPE (identifier)))
+ {
+ /* In G++ 3.2, the name mangling scheme was ambiguous. In later
+ versions of the ABI, this problem has been fixed. */
+ if (abi_version_at_least (2))
+ abort ();
+ error ("due to a defect in the G++ 3.2 ABI, G++ has assigned the "
+ "same mangled name to two different types");
+ }
+
/* Set bits on the identifier so we know later it's a conversion. */
IDENTIFIER_OPNAME_P (identifier) = 1;
IDENTIFIER_TYPENAME_P (identifier) = 1;
mangle_guard_variable (variable)
tree variable;
{
- start_mangling ();
+ start_mangling (variable);
write_string ("_ZGV");
- write_name (variable);
- return get_identifier (finish_mangling ());
+ 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 (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 (variable)
+ tree variable;
+{
+ start_mangling (variable);
+ write_string ("_ZGR");
+ write_name (variable, /*ignore_local_scope=*/0);
+ return get_identifier (finish_mangling (/*warn=*/false));
+}
+\f
+
+/* Foreign language type mangling section. */
+
+/* How to write the type codes for the integer Java type. */
+
+static void
+write_java_integer_type_codes (type)
+ 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
+ abort ();
+}
+