#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"
#ifndef DEBUG_MANGLE
#define DEBUG_MANGLE 0
#endif
#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
#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))))))
typedef struct globals GTY(())
{
VEC(tree,gc) *substitutions;
tree GTY ((skip)) entity;
bool need_abi_warning;
} globals;
static GTY (()) globals G;
static struct obstack *mangle_obstack;
static struct obstack name_obstack;
static void *name_base;
static char *partially_mangled_name;
static size_t partially_mangled_name_len;
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;
static GTY(()) tree subst_identifiers[SUBID_MAX];
static const char
integer_type_codes[itk_none] =
{
'c',
'a',
'h',
's',
't',
'i',
'j',
'l',
'm',
'x',
'y'
};
static int decl_is_template_id (const tree, tree* const);
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);
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);
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 *);
static void write_java_integer_type_codes (const tree);
#define write_char(CHAR) \
obstack_1grow (mangle_obstack, (CHAR))
#define write_chars(CHAR, LEN) \
obstack_grow (mangle_obstack, (CHAR), (LEN))
#define write_string(STRING) \
obstack_grow (mangle_obstack, (STRING), strlen (STRING))
#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))
#define write_unsigned_number(NUMBER) \
write_number ((NUMBER), 1, 10)
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));
}
}
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;
}
}
static int
decl_is_template_id (const tree decl, tree* const template_info)
{
if (TREE_CODE (decl) == TYPE_DECL)
{
const tree type = TREE_TYPE (decl);
if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_ID_P (type))
{
if (template_info != NULL)
*template_info = TYPE_TEMPLATE_INFO (type);
return 1;
}
}
else
{
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)
*template_info = DECL_TEMPLATE_INFO (decl);
return 1;
}
}
return 0;
}
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);
}
}
static inline tree
canonicalize_for_substitution (tree node)
{
if (TREE_CODE (node) == TYPE_DECL)
node = TREE_TYPE (node);
if (TYPE_P (node))
node = canonical_type_variant (node);
return node;
}
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);
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
{
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
VEC_safe_push (tree, gc, G.substitutions, node);
if (DEBUG_MANGLE)
dump_substitution_candidates ();
}
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
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]));
}
static inline int
is_std_substitution_char (const tree node,
const substitution_identifier_index_t index)
{
tree args;
if (!is_std_substitution (node, index))
return 0;
if (DECL_P (node))
args = DECL_TI_ARGS (node);
else if (CLASS_TYPE_P (node))
args = CLASSTYPE_TI_ARGS (node);
else
return 0;
return
TREE_VEC_LENGTH (args) == 1
&& TREE_VEC_ELT (args, 0) == char_type_node;
}
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);
node = canonicalize_for_substitution (node);
decl = TYPE_P (node) ? TYPE_NAME (node) : node;
type = TYPE_P (node) ? node : TREE_TYPE (node);
if (decl
&& is_std_substitution (decl, SUBID_ALLOCATOR)
&& !CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)))
{
write_string ("Sa");
return 1;
}
if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
{
if (TYPE_P (node))
{
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
{
write_string ("Sb");
return 1;
}
}
if (TYPE_P (node)
&& cp_type_quals (type) == TYPE_UNQUALIFIED
&& CLASS_TYPE_P (type)
&& CLASSTYPE_USE_TEMPLATE (type)
&& CLASSTYPE_TEMPLATE_INFO (type) != NULL)
{
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))
{
if (is_std_substitution (decl, SUBID_BASIC_ISTREAM))
{
write_string ("Si");
return 1;
}
else if (is_std_substitution (decl, SUBID_BASIC_OSTREAM))
{
write_string ("So");
return 1;
}
else if (is_std_substitution (decl, SUBID_BASIC_IOSTREAM))
{
write_string ("Sd");
return 1;
}
}
}
if (decl && DECL_NAMESPACE_STD_P (decl))
{
write_string ("St");
return 1;
}
for (i = 0; i < size; ++i)
{
tree candidate = VEC_index (tree, G.substitutions, i);
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;
}
}
return 0;
}
static void
write_mangled_name (const tree decl, bool top_level)
{
MANGLE_TRACE_TREE ("mangled-name", decl);
if (
DECL_EXTERN_C_FUNCTION_P (decl)
&& !DECL_OVERLOADED_OPERATOR_P (decl))
{
unmangled_name:;
if (top_level)
write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
else
{
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
\
&& DECL_EXTERNAL_LINKAGE_P (decl)
\
&& (CP_DECL_CONTEXT (decl) == global_namespace
|| 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)))
write_string (" *INTERNAL* ");
}
}
static void
write_encoding (const tree decl)
{
MANGLE_TRACE_TREE ("encoding", decl);
if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl))
{
if (DECL_OVERLOADED_OPERATOR_P (decl))
write_name (decl, 0);
else
write_source_name (DECL_NAME (decl));
return;
}
write_name (decl, 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 ();
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);
}
}
static void
write_name (tree decl, const int ignore_local_scope)
{
tree context;
MANGLE_TRACE_TREE ("name", decl);
if (TREE_CODE (decl) == TYPE_DECL)
{
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);
if (context == NULL
|| context == global_namespace
|| DECL_NAMESPACE_STD_P (context)
|| (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL))
{
tree template_info;
if (decl_is_template_id (decl, &template_info))
{
write_unscoped_template_name (TI_TEMPLATE (template_info));
write_template_args (TI_ARGS (template_info));
}
else
write_unscoped_name (decl);
}
else
{
if (!ignore_local_scope)
{
tree local_entity = decl;
while (context != NULL && context != global_namespace)
{
if (context != NULL && TYPE_P (context))
context = TYPE_NAME (context);
if (TREE_CODE (context) == FUNCTION_DECL)
{
write_local_name (context, local_entity, decl);
return;
}
local_entity = context;
context = CP_DECL_CONTEXT (context);
}
}
write_nested_name (decl);
}
}
static void
write_unscoped_name (const tree decl)
{
tree context = CP_DECL_CONTEXT (decl);
MANGLE_TRACE_TREE ("unscoped-name", decl);
if (DECL_NAMESPACE_STD_P (context))
{
write_string ("St");
write_unqualified_name (decl);
}
else
{
gcc_assert (context == global_namespace
|| context == NULL
|| TREE_CODE (context) == FUNCTION_DECL);
write_unqualified_name (decl);
}
}
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);
}
static void
write_nested_name (const tree decl)
{
tree template_info;
MANGLE_TRACE_TREE ("nested-name", decl);
write_char ('N');
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');
}
if (decl_is_template_id (decl, &template_info))
{
write_template_prefix (decl);
write_template_args (TI_ARGS (template_info));
}
else
{
write_prefix (DECL_CONTEXT (decl));
write_unqualified_name (decl);
}
write_char ('E');
}
static void
write_prefix (const tree node)
{
tree decl;
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 (TREE_CODE (node) == FUNCTION_DECL)
return;
decl = node;
decl_is_template_id (decl, &template_info);
}
else
{
decl = TYPE_NAME (node);
if (CLASSTYPE_TEMPLATE_ID_P (node))
template_info = TYPE_TEMPLATE_INFO (node);
}
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)
{
write_template_prefix (decl);
write_template_args (TI_ARGS (template_info));
}
else
{
write_prefix (CP_DECL_CONTEXT (decl));
write_unqualified_name (decl);
}
add_substitution (node);
}
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);
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);
}
if (TYPE_P (context))
substitution = build_tree_list (context, template);
else
substitution = template;
if (find_substitution (substitution))
return;
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);
}
\
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))
{
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);
}
\
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));
}
\
else
write_source_name (DECL_NAME (decl));
}
static void
write_conversion_operator_name (const tree type)
{
write_string ("cv");
write_type (type);
}
static void
write_source_name (tree identifier)
{
MANGLE_TRACE_TREE ("source-name", identifier);
if (IDENTIFIER_TEMPLATE (identifier))
identifier = IDENTIFIER_TEMPLATE (identifier);
write_unsigned_number (IDENTIFIER_LENGTH (identifier));
write_identifier (IDENTIFIER_POINTER (identifier));
}
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;
}
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);
}
static inline void
write_integer_cst (const tree cst)
{
int sign = tree_int_cst_sgn (cst);
if (TREE_INT_CST_HIGH (cst) + (sign < 0))
{
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;
chunk = 1000000000;
chunk_digits = 9;
if (sizeof (HOST_WIDE_INT) >= 8)
{
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
{
unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
if (sign < 0)
{
write_char ('n');
low = -low;
}
write_unsigned_number (low);
}
}
static void
write_real_cst (const tree value)
{
if (abi_version_at_least (2))
{
long target_real[4];
char buffer[9];
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));
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
{
size_t i;
for (i = 0; i < sizeof (TREE_REAL_CST (value)); ++i)
write_number (((unsigned char *) &TREE_REAL_CST (value))[i],
1,
16);
G.need_abi_warning = 1;
}
}
static void
write_identifier (const char *identifier)
{
MANGLE_TRACE ("identifier", identifier);
write_string (identifier);
}
static void
write_special_name_constructor (const tree ctor)
{
if (DECL_BASE_CONSTRUCTOR_P (ctor))
write_string ("C2");
else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
write_string ("C4");
else
{
gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
|| DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor));
write_string ("C1");
}
}
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");
else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
write_string ("D4");
else
{
gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor)
|| DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor));
write_string ("D1");
}
}
static int
discriminator_for_local_entity (tree entity)
{
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;
entity = TREE_TYPE (entity);
for (ix = 0; ; ix++)
{
tree type = VEC_index (tree, local_classes, ix);
if (type == entity)
break;
if (TYPE_IDENTIFIER (type) == TYPE_IDENTIFIER (entity)
&& TYPE_CONTEXT (type) == TYPE_CONTEXT (entity))
++discriminator;
}
}
return discriminator;
}
static int
discriminator_for_string_literal (tree function ATTRIBUTE_UNUSED,
tree string ATTRIBUTE_UNUSED)
{
return 0;
}
static void
write_discriminator (const int discriminator)
{
if (discriminator > 0)
{
write_char ('_');
write_unsigned_number (discriminator - 1);
}
}
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
{
write_name (entity, 1);
write_discriminator (discriminator_for_local_entity (local_entity));
}
}
static void
write_type (tree 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)
write_type (TYPE_MAIN_VARIANT (type));
else if (TREE_CODE (type) == ARRAY_TYPE)
write_array_type (type);
else
{
type = TYPE_MAIN_VARIANT (type);
if (TYPE_PTRMEM_P (type))
write_pointer_to_member_type (type);
else switch (TREE_CODE (type))
{
case VOID_TYPE:
case BOOLEAN_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
{
const char *target_mangling
= targetm.mangle_fundamental_type (type);
if (target_mangling)
{
write_string (target_mangling);
return;
}
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:
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:
write_nested_name (TYPE_STUB_DECL (type));
break;
case POINTER_TYPE:
write_char ('P');
write_type (TREE_TYPE (type));
break;
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 ();
}
}
if (!is_builtin_type)
add_substitution (type);
}
static int
write_CV_qualifiers_for_type (const tree type)
{
int num_qualifiers = 0;
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;
}
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 (TYPE_IS_SIZETYPE (type))
type = TYPE_DOMAIN (type);
if (type == wchar_type_node)
write_char ('w');
else if (TYPE_FOR_JAVA (type))
write_java_integer_type_codes (type);
else
{
size_t itk;
iagain:
for (itk = 0; itk < itk_none; ++itk)
if (type == integer_types[itk])
{
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
{
const char *prefix;
char prec[11];
prefix = TYPE_UNSIGNED (type) ? "uint" : "int";
sprintf (prec, "%u", (unsigned) TYPE_PRECISION (type));
write_char ('u');
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 ();
}
}
static void
write_function_type (const tree type)
{
MANGLE_TRACE_TREE ("function-type", type);
if (TREE_CODE (type) == METHOD_TYPE)
{
tree this_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
write_CV_qualifiers_for_type (this_type);
}
write_char ('F');
write_bare_function_type (type, 1,
NULL);
write_char ('E');
}
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);
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;
}
if (include_return_type_p || java_method_p)
write_type (TREE_TYPE (type));
write_method_parms (TYPE_ARG_TYPES (type),
TREE_CODE (type) == METHOD_TYPE,
decl);
}
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;
int varargs_p = 1;
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)
{
if (parm_types == first_parm_type)
write_type (parm);
varargs_p = 0;
gcc_assert (TREE_CHAIN (parm_types) == NULL);
}
else
write_type (parm);
}
if (varargs_p)
write_char ('z');
}
static void
write_class_enum_type (const tree type)
{
write_name (TYPE_NAME (type), 0);
}
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)
{
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');
}
static void
write_expression (tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
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);
}
if (code == PTRMEM_CST)
{
expr = build_nt (ADDR_EXPR,
build_qualified_name (NULL_TREE,
PTRMEM_CST_CLASS (expr),
PTRMEM_CST_MEMBER (expr),
false));
code = TREE_CODE (expr);
}
if (code == TEMPLATE_TYPE_PARM
|| code == TEMPLATE_TEMPLATE_PARM
|| code == BOUND_TEMPLATE_TEMPLATE_PARM
|| code == TEMPLATE_PARM_INDEX)
write_template_param (expr);
else if (TREE_CODE_CLASS (code) == tcc_constant
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (expr);
else if (DECL_P (expr))
{
if (code == CONST_DECL)
G.need_abi_warning = 1;
write_char ('L');
write_mangled_name (expr, 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 (DECL_P (member))
write_expression (member);
else
{
tree template_args;
write_string ("sr");
write_type (scope);
if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
{
template_args = TREE_OPERAND (member, 1);
member = TREE_OPERAND (member, 0);
}
else
template_args = NULL_TREE;
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;
for (i = 0; i < LAST_CPLUS_TREE_CODE; ++i)
if (operator_name_info[i].identifier == member)
{
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);
if (template_args)
write_template_args (template_args);
}
}
else
{
int i;
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);
}
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));
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;
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);
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.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);
if (code == COND_EXPR && i == 1 && !operand)
{
error ("omitted middle operand to %<?:%> operand "
"cannot be mangled");
continue;
}
write_expression (operand);
}
}
}
}
static void
write_template_arg_literal (const tree value)
{
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');
}
static void
write_template_arg (tree node)
{
enum tree_code code = TREE_CODE (node);
MANGLE_TRACE_TREE ("template-arg", node);
if (code == TREE_LIST)
{
node = TREE_VALUE (node);
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)
{
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)
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))
{
if (code == CONST_DECL && !abi_version_at_least (2))
G.need_abi_warning = 1;
write_char ('L');
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
{
write_char ('X');
write_expression (node);
write_char ('E');
}
}
static void
write_template_template_arg (const tree decl)
{
MANGLE_TRACE_TREE ("template-template-arg", decl);
if (find_substitution (decl))
return;
write_name (decl, 0);
add_substitution (decl);
}
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);
max = TYPE_MAX_VALUE (index_type);
if (TREE_CODE (max) == INTEGER_CST)
{
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))
{
++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));
}
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));
}
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');
if (parm_index > 0)
write_unsigned_number (parm_index - 1);
write_char ('_');
}
static void
write_template_template_param (const tree parm)
{
tree template = NULL_TREE;
if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
template
= TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
if (find_substitution (template))
return;
}
write_template_param (parm);
if (template)
add_substitution (template);
}
static void
write_substitution (const int seq_id)
{
MANGLE_TRACE ("substitution", "");
write_char ('S');
if (seq_id > 0)
write_number (seq_id - 1, 1, 36);
write_char ('_');
}
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;
}
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);
VEC_truncate (tree, G.substitutions, 0);
write_char ('\0');
return (const char *) obstack_finish (mangle_obstack);
}
void
init_mangle (void)
{
gcc_obstack_init (&name_obstack);
name_base = obstack_alloc (&name_obstack, 0);
G.substitutions = NULL;
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");
}
static const char *
mangle_decl_string (const tree decl)
{
const char *result;
start_mangling (decl, true);
if (TREE_CODE (decl) == TYPE_DECL)
write_type (TREE_TYPE (decl));
else
write_mangled_name (decl, true);
result = finish_mangling (true);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
return result;
}
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);
}
void
mangle_decl (const tree decl)
{
SET_DECL_ASSEMBLER_NAME (decl,
get_identifier_nocopy (mangle_decl_string (decl)));
}
const char *
mangle_type_string (const tree type)
{
const char *result;
start_mangling (type, false);
write_type (type);
result = finish_mangling (false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
return result;
}
static tree
mangle_special_for_type (const tree type, const char *code)
{
const char *result;
start_mangling (type, true);
write_string ("_Z");
write_string (code);
write_type (type);
result = finish_mangling (false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
return get_identifier_nocopy (result);
}
tree
mangle_typeinfo_for_type (const tree type)
{
return mangle_special_for_type (type, "TI");
}
tree
mangle_typeinfo_string_for_type (const tree type)
{
return mangle_special_for_type (type, "TS");
}
tree
mangle_vtbl_for_type (const tree type)
{
return mangle_special_for_type (type, "TV");
}
tree
mangle_vtt_for_type (const tree type)
{
return mangle_special_for_type (type, "TT");
}
tree
mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
{
const char *result;
start_mangling (type, 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 (false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
return get_identifier_nocopy (result);
}
static void
mangle_call_offset (const tree fixed_offset, const tree virtual_offset)
{
write_char (virtual_offset ? 'v' : 'h');
write_integer_cst (fixed_offset);
write_char ('_');
if (virtual_offset)
{
write_integer_cst (virtual_offset);
write_char ('_');
}
}
tree
mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
tree virtual_offset)
{
const char *result;
start_mangling (fn_decl, true);
write_string ("_Z");
write_char ('T');
if (!this_adjusting)
{
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))
mangle_call_offset (fixed_offset, virtual_offset);
else
{
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);
}
write_encoding (fn_decl);
result = finish_mangling (false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", result);
return get_identifier_nocopy (result);
}
static GTY ((param_is (union tree_node))) htab_t conv_type_names;
static hashval_t
hash_type (const void *val)
{
return (hashval_t) TYPE_UID (TREE_TYPE ((tree) val));
}
static int
compare_type (const void *val1, const void *val2)
{
return TREE_TYPE ((tree) val1) == (tree) val2;
}
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];
sprintf (buffer, "operator %lu",
(unsigned long) htab_elements (conv_type_names));
identifier = get_identifier (buffer);
*slot = identifier;
TREE_TYPE (identifier) = type;
IDENTIFIER_OPNAME_P (identifier) = 1;
IDENTIFIER_TYPENAME_P (identifier) = 1;
}
return identifier;
}
tree
mangle_guard_variable (const tree variable)
{
start_mangling (variable, true);
write_string ("_ZGV");
if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
else
write_name (variable, 0);
return get_identifier_nocopy (finish_mangling (false));
}
tree
mangle_ref_init_variable (const tree variable)
{
start_mangling (variable, true);
write_string ("_ZGR");
write_name (variable, 0);
return get_identifier_nocopy (finish_mangling (false));
}
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"