/* Name mangling for the 3.0 C++ ABI.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com>
This file is part of GCC.
#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"
+#include "cgraph.h"
/* Debugging support. */
&& (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
/* Things we only need one of. This module is not reentrant. */
-typedef struct globals GTY(())
-{
+typedef struct GTY(()) globals {
/* An array of the current substitution candidates, in the order
we've seen them. */
VEC(tree,gc) *substitutions;
/* The entity that is being mangled. */
tree GTY ((skip)) entity;
+ /* How many parameter scopes we are inside. */
+ int parm_depth;
+
/* True if the mangling will be different in a future version of the
ABI. */
bool need_abi_warning;
'l', /* itk_long */
'm', /* itk_unsigned_long */
'x', /* itk_long_long */
- 'y' /* itk_unsigned_long_long */
+ 'y', /* itk_unsigned_long_long */
+ 'n', /* itk_int128 */
+ 'o', /* itk_unsigned_int128 */
};
static int decl_is_template_id (const tree, tree* const);
static void write_unqualified_name (const tree);
static void write_conversion_operator_name (const tree);
static void write_source_name (tree);
+static void write_literal_operator_name (tree);
+static void write_unnamed_type_name (const tree);
+static void write_closure_type_name (const 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_compact_number (int num);
static void write_integer_cst (const tree);
static void write_real_cst (const tree);
static void write_identifier (const char *);
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 write_local_name (tree, const tree, const tree);
static void dump_substitution_candidates (void);
static tree mangle_decl_string (const tree);
+static int local_class_index (tree);
/* Control functions. */
tree el;
fprintf (stderr, " ++ substitutions ");
- for (i = 0; VEC_iterate (tree, G.substitutions, i, el); ++i)
+ FOR_EACH_VEC_ELT (tree, G.substitutions, i, el)
{
const char *name = "???";
/* 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);
-
+ if (TYPE_P (node)
+ && TYPE_CANONICAL (node) != node
+ && TYPE_MAIN_VARIANT (node) != node)
+ {
+ /* Here we want to strip the topmost typedef only.
+ We need to do that so is_std_substitution can do proper
+ name matching. */
+ if (TREE_CODE (node) == FUNCTION_TYPE)
+ /* Use build_qualified_type and TYPE_QUALS here to preserve
+ the old buggy mangling of attribute noreturn with abi<5. */
+ node = build_qualified_type (TYPE_MAIN_VARIANT (node),
+ TYPE_QUALS (node));
+ else
+ node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
+ cp_type_quals (node));
+ }
return node;
}
int i;
tree candidate;
- for (i = 0; VEC_iterate (tree, G.substitutions, i, candidate); i++)
+ FOR_EACH_VEC_ELT (tree, G.substitutions, i, candidate)
{
gcc_assert (!(DECL_P (node) && node == candidate));
gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
/* NODE is a matched to a candidate if it's the same decl node or
if it's the same type. */
if (decl == candidate
- || (TYPE_P (candidate) && type && TYPE_P (type)
+ || (TYPE_P (candidate) && type && TYPE_P (node)
&& same_type_p (type, candidate))
|| NESTED_TEMPLATE_MATCH (node, candidate))
{
}
}
+/* Lambdas can have a bit more context for mangling, specifically VAR_DECL
+ or PARM_DECL context, which doesn't belong in DECL_CONTEXT. */
+
+static tree
+decl_mangling_context (tree decl)
+{
+ tree tcontext = targetm.cxx.decl_mangling_context (decl);
+
+ if (tcontext != NULL_TREE)
+ return tcontext;
+
+ if (TREE_CODE (decl) == TYPE_DECL
+ && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+ {
+ tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl));
+ if (extra)
+ return extra;
+ }
+ else if (TREE_CODE (decl) == TYPE_DECL
+ && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM)
+ /* template type parms have no mangling context. */
+ return NULL_TREE;
+ return CP_DECL_CONTEXT (decl);
+}
+
/* <name> ::= <unscoped-name>
::= <unscoped-template-name> <template-args>
::= <nested-name>
/* 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);
+
+ context = decl_mangling_context (decl);
/* A decl in :: or ::std scope is treated specially. The former is
mangled using <unscoped-name> or <unscoped-template-name>, the
if (context != NULL && TYPE_P (context))
context = TYPE_NAME (context);
/* Is this a function? */
- if (TREE_CODE (context) == FUNCTION_DECL)
+ if (TREE_CODE (context) == FUNCTION_DECL
+ || TREE_CODE (context) == PARM_DECL)
{
/* Yes, we have local scope. Use the <local-name>
production for the innermost function scope. */
}
/* Up one scope level. */
local_entity = context;
- context = CP_DECL_CONTEXT (context);
+ context = decl_mangling_context (context);
}
/* No local scope found? Fall through to <nested-name>. */
static void
write_unscoped_name (const tree decl)
{
- tree context = CP_DECL_CONTEXT (decl);
+ tree context = decl_mangling_context (decl);
MANGLE_TRACE_TREE ("unscoped-name", decl);
/* If not, it should be either in the global namespace, or directly
in a local function scope. */
gcc_assert (context == global_namespace
- || context == NULL
+ || context != NULL
|| TREE_CODE (context) == FUNCTION_DECL);
write_unqualified_name (decl);
write_template_prefix (decl);
write_template_args (TI_ARGS (template_info));
}
+ else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+ {
+ tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ write_template_prefix (decl);
+ write_template_args (TREE_OPERAND (name, 1));
+ }
+ else
+ {
+ write_prefix (CP_DECL_CONTEXT (decl));
+ write_unqualified_name (decl);
+ }
+ }
else
{
/* No, just use <prefix> */
- write_prefix (DECL_CONTEXT (decl));
+ write_prefix (decl_mangling_context (decl));
write_unqualified_name (decl);
}
write_char ('E');
/* <prefix> ::= <prefix> <unqualified-name>
::= <template-param>
::= <template-prefix> <template-args>
+ ::= <decltype>
::= # empty
::= <substitution> */
/* 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);
+
+ if (TREE_CODE (node) == DECLTYPE_TYPE)
+ {
+ write_type (node);
+ return;
+ }
+
if (find_substitution (node))
return;
if (DECL_P (node))
{
- /* If this is a function decl, that means we've hit function
+ /* If this is a function or parm 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)
+ if (TREE_CODE (node) == FUNCTION_DECL
+ || TREE_CODE (node) == PARM_DECL)
return;
decl = node;
write_template_prefix (decl);
write_template_args (TI_ARGS (template_info));
}
+ else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+ {
+ tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ write_template_prefix (decl);
+ write_template_args (TREE_OPERAND (name, 1));
+ }
+ else
+ {
+ write_prefix (CP_DECL_CONTEXT (decl));
+ write_unqualified_name (decl);
+ }
+ }
else
/* Not templated. */
{
- write_prefix (CP_DECL_CONTEXT (decl));
+ write_prefix (decl_mangling_context (decl));
write_unqualified_name (decl);
+ if (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FIELD_DECL)
+ {
+ /* <data-member-prefix> := <member source-name> M */
+ write_char ('M');
+ return;
+ }
}
add_substitution (node);
tree type = DECL_P (node) ? TREE_TYPE (node) : node;
tree context = CP_DECL_CONTEXT (decl);
tree template_info;
- tree template;
+ tree templ;
tree substitution;
MANGLE_TRACE_TREE ("template-prefix", node);
/* Find the template decl. */
if (decl_is_template_id (decl, &template_info))
- template = TI_TEMPLATE (template_info);
+ templ = TI_TEMPLATE (template_info);
+ else if (TREE_CODE (type) == TYPENAME_TYPE)
+ /* For a typename type, all we have is the name. */
+ templ = DECL_NAME (decl);
else
{
gcc_assert (CLASSTYPE_TEMPLATE_ID_P (type));
- template = TYPE_TI_TEMPLATE (type);
+ templ = TYPE_TI_TEMPLATE (type);
}
/* For a member template, though, the template name for the
substitution candidate by a TREE_LIST whose purpose is `Outer<int>'
and whose value is `Outer<T>::Inner<U>'. */
if (TYPE_P (context))
- substitution = build_tree_list (context, template);
+ substitution = build_tree_list (context, templ);
else
- substitution = template;
+ substitution = templ;
if (find_substitution (substitution))
return;
/* In G++ 3.2, the name of the template template parameter was used. */
- if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+ if (TREE_TYPE (templ)
+ && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
&& !abi_version_at_least (2))
G.need_abi_warning = true;
- if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+ if (TREE_TYPE (templ)
+ && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
&& abi_version_at_least (2))
- write_template_param (TREE_TYPE (template));
+ write_template_param (TREE_TYPE (templ));
else
{
write_prefix (context);
<unqualified-name> ::= <operator-name>
::= <special-name>
::= <source-name>
+ ::= <unnamed-type-name>
::= <local-source-name>
<local-source-name> ::= L <source-name> <discriminator> */
static void
+write_unqualified_id (tree identifier)
+{
+ if (IDENTIFIER_TYPENAME_P (identifier))
+ write_conversion_operator_name (TREE_TYPE (identifier));
+ else if (IDENTIFIER_OPNAME_P (identifier))
+ {
+ 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 < MAX_TREE_CODES; ++i)
+ if (operator_name_info[i].identifier == identifier)
+ {
+ /* 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
+ == identifier)
+ {
+ mangled_name
+ = assignment_operator_name_info[i].mangled_name;
+ break;
+ }
+ write_string (mangled_name);
+ }
+ else if (UDLIT_OPER_P (identifier))
+ write_literal_operator_name (identifier);
+ else
+ write_source_name (identifier);
+}
+
+static void
write_unqualified_name (const tree decl)
{
MANGLE_TRACE_TREE ("unqualified-name", decl);
- if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_CONSTRUCTOR_P (decl))
- write_special_name_constructor (decl);
- else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
- write_special_name_destructor (decl);
- else if (DECL_NAME (decl) == NULL_TREE)
- write_source_name (DECL_ASSEMBLER_NAME (decl));
- else if (DECL_CONV_FN_P (decl))
- {
- /* Conversion operator. Handle it right here.
- <operator> ::= cv <type> */
- tree type;
- if (decl_is_template_id (decl, NULL))
- {
- tree fn_type;
- fn_type = get_mostly_instantiated_function_type (decl);
- type = TREE_TYPE (fn_type);
- }
- else
- type = DECL_CONV_FN_TYPE (decl);
- write_conversion_operator_name (type);
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ {
+ write_unqualified_id (decl);
+ return;
}
- else if (DECL_OVERLOADED_OPERATOR_P (decl))
+
+ if (DECL_NAME (decl) == NULL_TREE)
{
- operator_name_info_t *oni;
- if (DECL_ASSIGNMENT_OPERATOR_P (decl))
- oni = assignment_operator_name_info;
+ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+ write_source_name (DECL_ASSEMBLER_NAME (decl));
+ return;
+ }
+ else if (DECL_DECLARES_FUNCTION_P (decl))
+ {
+ bool found = true;
+ if (DECL_CONSTRUCTOR_P (decl))
+ write_special_name_constructor (decl);
+ else if (DECL_DESTRUCTOR_P (decl))
+ write_special_name_destructor (decl);
+ else if (DECL_CONV_FN_P (decl))
+ {
+ /* Conversion operator. Handle it right here.
+ <operator> ::= cv <type> */
+ tree type;
+ if (decl_is_template_id (decl, NULL))
+ {
+ tree fn_type;
+ fn_type = get_mostly_instantiated_function_type (decl);
+ 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 (UDLIT_OPER_P (DECL_NAME (decl)))
+ write_literal_operator_name (DECL_NAME (decl));
else
- oni = operator_name_info;
+ found = false;
- write_string (oni[DECL_OVERLOADED_OPERATOR_P (decl)].mangled_name);
+ if (found)
+ return;
}
- else if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
- && DECL_NAMESPACE_SCOPE_P (decl)
- && decl_linkage (decl) == lk_internal)
+
+ 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');
so there's no code to output one here. */
}
else
- write_source_name (DECL_NAME (decl));
+ {
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == TYPE_DECL
+ && TYPE_ANONYMOUS_P (type))
+ write_unnamed_type_name (type);
+ else if (TREE_CODE (decl) == TYPE_DECL
+ && LAMBDA_TYPE_P (type))
+ write_closure_type_name (type);
+ else
+ write_source_name (DECL_NAME (decl));
+ }
}
/* Write the unqualified-name for a conversion operator to TYPE. */
write_identifier (IDENTIFIER_POINTER (identifier));
}
+/* Write a user-defined literal operator.
+ IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */
+
+static void
+write_literal_operator_name (tree identifier)
+{
+ const char* suffix = UDLIT_OP_SUFFIX (identifier);
+ char* buffer = XNEWVEC (char, strlen (UDLIT_OP_MANGLED_PREFIX)
+ + strlen (suffix) + 10);
+ sprintf (buffer, UDLIT_OP_MANGLED_FORMAT, suffix);
+
+ write_unsigned_number (strlen (buffer));
+ write_identifier (buffer);
+}
+
+/* Encode 0 as _, and 1+ as n-1_. */
+
+static void
+write_compact_number (int num)
+{
+ if (num > 0)
+ write_unsigned_number (num - 1);
+ write_char ('_');
+}
+
+/* Return how many unnamed types precede TYPE in its enclosing class. */
+
+static int
+nested_anon_class_index (tree type)
+{
+ int index = 0;
+ tree member = TYPE_FIELDS (TYPE_CONTEXT (type));
+ for (; member; member = DECL_CHAIN (member))
+ if (DECL_IMPLICIT_TYPEDEF_P (member))
+ {
+ tree memtype = TREE_TYPE (member);
+ if (memtype == type)
+ return index;
+ else if (TYPE_ANONYMOUS_P (memtype))
+ ++index;
+ }
+
+ gcc_unreachable ();
+}
+
+/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
+
+static void
+write_unnamed_type_name (const tree type ATTRIBUTE_UNUSED)
+{
+ int discriminator;
+ MANGLE_TRACE_TREE ("unnamed-type-name", type);
+
+ if (TYPE_FUNCTION_SCOPE_P (type))
+ discriminator = local_class_index (type);
+ else if (TYPE_CLASS_SCOPE_P (type))
+ discriminator = nested_anon_class_index (type);
+ else
+ {
+ gcc_assert (no_linkage_check (type, /*relaxed_p=*/true));
+ /* Just use the old mangling at namespace scope. */
+ write_source_name (TYPE_IDENTIFIER (type));
+ return;
+ }
+
+ write_string ("Ut");
+ write_compact_number (discriminator);
+}
+
+/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+ <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters */
+
+static void
+write_closure_type_name (const tree type)
+{
+ tree fn = lambda_function (type);
+ tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
+ tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+
+ MANGLE_TRACE_TREE ("closure-type-name", type);
+
+ write_string ("Ul");
+ write_method_parms (parms, /*method_p=*/1, fn);
+ write_char ('E');
+ write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda));
+}
+
/* 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
if (sign < 0)
{
write_char ('n');
- n = fold_build1 (NEGATE_EXPR, type, n);
+ n = fold_build1_loc (input_location, NEGATE_EXPR, type, n);
}
do
{
- tree d = fold_build2 (FLOOR_DIV_EXPR, type, n, base);
- tree tmp = fold_build2 (MULT_EXPR, type, d, base);
+ tree d = fold_build2_loc (input_location, FLOOR_DIV_EXPR, type, n, base);
+ tree tmp = fold_build2_loc (input_location, MULT_EXPR, type, d, base);
unsigned c;
done = integer_zerop (d);
- tmp = fold_build2 (MINUS_EXPR, type, n, tmp);
+ tmp = fold_build2_loc (input_location, MINUS_EXPR, type, n, tmp);
c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
done ? 1 : chunk_digits);
ptr -= c;
}
}
+/* Scan the vector of local classes and return how many others with the
+ same name (or same no name) and context precede ENTITY. */
+
+static int
+local_class_index (tree entity)
+{
+ int ix, discriminator = 0;
+ tree name = (TYPE_ANONYMOUS_P (entity) ? NULL_TREE
+ : TYPE_IDENTIFIER (entity));
+ tree ctx = TYPE_CONTEXT (entity);
+ for (ix = 0; ; ix++)
+ {
+ tree type = VEC_index (tree, local_classes, ix);
+ if (type == entity)
+ return discriminator;
+ if (TYPE_CONTEXT (type) == ctx
+ && (name ? TYPE_IDENTIFIER (type) == name
+ : TYPE_ANONYMOUS_P (type)))
+ ++discriminator;
+ }
+ gcc_unreachable ();
+}
+
/* Return the discriminator for ENTITY appearing inside
FUNCTION. The discriminator is the lexical ordinal of VAR among
entities with the same name in the same FUNCTION. */
static int
discriminator_for_local_entity (tree entity)
{
- /* Assume this is the only local entity with this name. */
- int discriminator = 0;
-
- if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
- discriminator = DECL_DISCRIMINATOR (entity);
+ if (DECL_DISCRIMINATOR_P (entity))
+ {
+ if (DECL_DISCRIMINATOR_SET_P (entity))
+ return DECL_DISCRIMINATOR (entity);
+ else
+ /* The first entity with a particular name doesn't get
+ DECL_DISCRIMINATOR set up. */
+ return 0;
+ }
else if (TREE_CODE (entity) == TYPE_DECL)
{
- int ix;
-
/* Scan the list of local classes. */
entity = TREE_TYPE (entity);
- for (ix = 0; ; ix++)
- {
- tree type = VEC_index (tree, local_classes, ix);
- if (type == entity)
- break;
- if (TYPE_IDENTIFIER (type) == TYPE_IDENTIFIER (entity)
- && TYPE_CONTEXT (type) == TYPE_CONTEXT (entity))
- ++discriminator;
- }
- }
- return discriminator;
+ /* Lambdas and unnamed types have their own discriminators. */
+ if (LAMBDA_TYPE_P (entity) || TYPE_ANONYMOUS_P (entity))
+ return 0;
+
+ return local_class_index (entity);
+ }
+ else
+ gcc_unreachable ();
}
/* Return the discriminator for STRING, a string literal used inside
}
/* Mangle the name of a function-scope entity. FUNCTION is the
- FUNCTION_DECL for the enclosing function. ENTITY is the decl for
- the entity itself. LOCAL_ENTITY is the entity that's directly
- scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope
- of ENTITY.
+ FUNCTION_DECL for the enclosing function, or a PARM_DECL for lambdas in
+ default argument scope. ENTITY is the decl for the entity itself.
+ LOCAL_ENTITY is the entity that's directly scoped in FUNCTION_DECL,
+ either ENTITY itself or an enclosing scope of ENTITY.
<local-name> := Z <function encoding> E <entity name> [<discriminator>]
- := Z <function encoding> E s [<discriminator>] */
+ := Z <function encoding> E s [<discriminator>]
+ := Z <function encoding> Ed [ <parameter number> ] _ <entity name> */
static void
-write_local_name (const tree function, const tree local_entity,
+write_local_name (tree function, const tree local_entity,
const tree entity)
{
+ tree parm = NULL_TREE;
+
MANGLE_TRACE_TREE ("local-name", entity);
+ if (TREE_CODE (function) == PARM_DECL)
+ {
+ parm = function;
+ function = DECL_CONTEXT (parm);
+ }
+
write_char ('Z');
write_encoding (function);
write_char ('E');
+
+ /* For this purpose, parameters are numbered from right-to-left. */
+ if (parm)
+ {
+ tree t;
+ int i = 0;
+ for (t = DECL_ARGUMENTS (function); t; t = DECL_CHAIN (t))
+ {
+ if (t == parm)
+ i = 1;
+ else if (i)
+ ++i;
+ }
+ write_char ('d');
+ write_compact_number (i - 1);
+ }
+
if (TREE_CODE (entity) == STRING_CST)
{
write_char ('s');
<type> ::= Dt <expression> # decltype of an id-expression or
# class member access
<type> ::= DT <expression> # decltype of an expression
+ <type> ::= Dn # decltype of nullptr
TYPE is a type node. */
if (type == error_mark_node)
return;
+ type = canonicalize_for_substitution (type);
if (find_substitution (type))
return;
+
if (write_CV_qualifiers_for_type (type) > 0)
/* If TYPE was CV-qualified, we just wrote the qualifiers; now
mangle the unqualified type. The recursive call is needed here
/* See through any typedefs. */
type = TYPE_MAIN_VARIANT (type);
+ /* According to the C++ ABI, some library classes are passed the
+ same as the scalar type of their single member and use the same
+ mangling. */
+ if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
+ type = TREE_TYPE (first_field (type));
+
if (TYPE_PTRMEM_P (type))
write_pointer_to_member_type (type);
else
if (target_mangling)
{
write_string (target_mangling);
+ /* Add substitutions for types other than fundamental
+ types. */
+ if (TREE_CODE (type) != VOID_TYPE
+ && TREE_CODE (type) != INTEGER_TYPE
+ && TREE_CODE (type) != REAL_TYPE
+ && TREE_CODE (type) != BOOLEAN_TYPE)
+ add_substitution (type);
return;
}
case BOOLEAN_TYPE:
case INTEGER_TYPE: /* Includes wchar_t. */
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
{
/* If this is a typedef, TYPE may not be one of
the standard builtin type nodes, but an alias of one. Use
break;
case POINTER_TYPE:
- write_char ('P');
- write_type (TREE_TYPE (type));
- break;
-
case REFERENCE_TYPE:
- if (TYPE_REF_IS_RVALUE (type))
- write_char('O');
+ if (TREE_CODE (type) == POINTER_TYPE)
+ write_char ('P');
+ else if (TYPE_REF_IS_RVALUE (type))
+ write_char ('O');
else
write_char ('R');
- write_type (TREE_TYPE (type));
+ {
+ tree target = TREE_TYPE (type);
+ /* Attribute const/noreturn are not reflected in mangling.
+ We strip them here rather than at a lower level because
+ a typedef or template argument can have function type
+ with function-cv-quals (that use the same representation),
+ but you can't have a pointer/reference to such a type. */
+ if (abi_version_at_least (5)
+ && TREE_CODE (target) == FUNCTION_TYPE)
+ target = build_qualified_type (target, TYPE_UNQUALIFIED);
+ write_type (target);
+ }
break;
case TEMPLATE_TYPE_PARM:
break;
case VECTOR_TYPE:
- write_string ("U8__vector");
+ if (abi_version_at_least (4))
+ {
+ write_string ("Dv");
+ /* Non-constant vector size would be encoded with
+ _ expression, but we don't support that yet. */
+ write_unsigned_number (TYPE_VECTOR_SUBPARTS (type));
+ write_char ('_');
+ }
+ else
+ {
+ G.need_abi_warning = 1;
+ write_string ("U8__vector");
+ }
write_type (TREE_TYPE (type));
break;
case TYPE_PACK_EXPANSION:
- write_string ("U10__variadic");
+ write_string ("Dp");
write_type (PACK_EXPANSION_PATTERN (type));
break;
case DECLTYPE_TYPE:
+ /* These shouldn't make it into mangling. */
+ gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type)
+ && !DECLTYPE_FOR_LAMBDA_PROXY (type));
+
+ /* In ABI <5, we stripped decltype of a plain decl. */
+ if (!abi_version_at_least (5)
+ && DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
+ {
+ tree expr = DECLTYPE_TYPE_EXPR (type);
+ tree etype = NULL_TREE;
+ switch (TREE_CODE (expr))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case FUNCTION_DECL:
+ case CONST_DECL:
+ case TEMPLATE_PARM_INDEX:
+ etype = TREE_TYPE (expr);
+ break;
+
+ default:
+ break;
+ }
+
+ if (etype && !type_uses_auto (etype))
+ {
+ G.need_abi_warning = 1;
+ write_type (etype);
+ return;
+ }
+ }
+
write_char ('D');
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
write_char ('t');
else
write_char ('T');
+ ++cp_unevaluated_operand;
write_expression (DECLTYPE_TYPE_EXPR (type));
+ --cp_unevaluated_operand;
write_char ('E');
break;
+ case NULLPTR_TYPE:
+ write_string ("Dn");
+ break;
+
case TYPEOF_TYPE:
sorry ("mangling typeof, use decltype instead");
break;
+ case UNDERLYING_TYPE:
+ sorry ("mangling __underlying_type");
+ break;
+
+ case LANG_TYPE:
+ /* fall through. */
+
default:
gcc_unreachable ();
}
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. */
+ cp_cv_quals quals = TYPE_QUALS (type);
- if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
+ if (quals & TYPE_QUAL_RESTRICT)
{
write_char ('r');
++num_qualifiers;
}
- if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+ if (quals & TYPE_QUAL_VOLATILE)
{
write_char ('V');
++num_qualifiers;
}
- if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
+ if (quals & TYPE_QUAL_CONST)
{
write_char ('K');
++num_qualifiers;
if (type == wchar_type_node)
write_char ('w');
else if (type == char16_type_node)
- write_string ("u8char16_t");
+ write_string ("Ds");
else if (type == char32_type_node)
- write_string ("u8char32_t");
+ write_string ("Di");
else if (TYPE_FOR_JAVA (type))
write_java_integer_type_codes (type);
else
it in the array of these nodes. */
iagain:
for (itk = 0; itk < itk_none; ++itk)
- if (type == integer_types[itk])
+ if (integer_types[itk] != NULL_TREE
+ && type == integer_types[itk])
{
/* Print the corresponding single-letter code. */
write_char (integer_type_codes[itk]);
write_char ('d');
else if (type == long_double_type_node)
write_char ('e');
+ else if (type == dfloat32_type_node)
+ write_string ("Df");
+ else if (type == dfloat64_type_node)
+ write_string ("Dd");
+ else if (type == dfloat128_type_node)
+ write_string ("De");
else
gcc_unreachable ();
break;
+ case FIXED_POINT_TYPE:
+ write_string ("DF");
+ if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
+ write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
+ if (type == fract_type_node
+ || type == sat_fract_type_node
+ || type == accum_type_node
+ || type == sat_accum_type_node)
+ write_char ('i');
+ else if (type == unsigned_fract_type_node
+ || type == sat_unsigned_fract_type_node
+ || type == unsigned_accum_type_node
+ || type == sat_unsigned_accum_type_node)
+ write_char ('j');
+ else if (type == short_fract_type_node
+ || type == sat_short_fract_type_node
+ || type == short_accum_type_node
+ || type == sat_short_accum_type_node)
+ write_char ('s');
+ else if (type == unsigned_short_fract_type_node
+ || type == sat_unsigned_short_fract_type_node
+ || type == unsigned_short_accum_type_node
+ || type == sat_unsigned_short_accum_type_node)
+ write_char ('t');
+ else if (type == long_fract_type_node
+ || type == sat_long_fract_type_node
+ || type == long_accum_type_node
+ || type == sat_long_accum_type_node)
+ write_char ('l');
+ else if (type == unsigned_long_fract_type_node
+ || type == sat_unsigned_long_fract_type_node
+ || type == unsigned_long_accum_type_node
+ || type == sat_unsigned_long_accum_type_node)
+ write_char ('m');
+ else if (type == long_long_fract_type_node
+ || type == sat_long_long_fract_type_node
+ || type == long_long_accum_type_node
+ || type == sat_long_long_accum_type_node)
+ write_char ('x');
+ else if (type == unsigned_long_long_fract_type_node
+ || type == sat_unsigned_long_long_fract_type_node
+ || type == unsigned_long_long_accum_type_node
+ || type == sat_unsigned_long_long_accum_type_node)
+ write_char ('y');
+ else
+ sorry ("mangling unknown fixed point type");
+ write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
+ if (TYPE_SATURATING (type))
+ write_char ('s');
+ else
+ write_char ('n');
+ break;
+
default:
gcc_unreachable ();
}
{
/* The first parameter must be a POINTER_TYPE pointing to the
`this' parameter. */
- tree this_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
+ tree this_type = class_of_this_parm (type);
write_CV_qualifiers_for_type (this_type);
}
write_type (TREE_TYPE (type));
/* Now mangle the types of the arguments. */
+ ++G.parm_depth;
write_method_parms (TYPE_ARG_TYPES (type),
TREE_CODE (type) == METHOD_TYPE,
decl);
+ --G.parm_depth;
}
/* Write the mangled representation of a method parameter list of
if (method_p)
{
parm_types = TREE_CHAIN (parm_types);
- parm_decl = parm_decl ? TREE_CHAIN (parm_decl) : NULL_TREE;
+ parm_decl = parm_decl ? DECL_CHAIN (parm_decl) : NULL_TREE;
while (parm_decl && DECL_ARTIFICIAL (parm_decl))
{
parm_types = TREE_CHAIN (parm_types);
- parm_decl = TREE_CHAIN (parm_decl);
+ parm_decl = DECL_CHAIN (parm_decl);
}
}
/* Non-terminal <template-args>. ARGS is a TREE_VEC of template
arguments.
- <template-args> ::= I <template-arg>+ E */
+ <template-args> ::= I <template-arg>* E */
static void
write_template_args (tree args)
{
int i;
- int length = TREE_VEC_LENGTH (args);
+ int length = 0;
MANGLE_TRACE_TREE ("template-args", args);
write_char ('I');
- gcc_assert (length > 0);
+ if (args)
+ length = TREE_VEC_LENGTH (args);
- if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ if (args && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
{
/* We have nested template args. We want the innermost template
argument list. */
write_char ('E');
}
+/* Write out the
+ <unqualified-name>
+ <unqualified-name> <template-args>
+ part of SCOPE_REF or COMPONENT_REF mangling. */
+
+static void
+write_member_name (tree member)
+{
+ if (TREE_CODE (member) == IDENTIFIER_NODE)
+ write_unqualified_id (member);
+ else if (DECL_P (member))
+ write_unqualified_name (member);
+ else if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
+ {
+ tree name = TREE_OPERAND (member, 0);
+ if (TREE_CODE (name) == OVERLOAD)
+ name = OVL_FUNCTION (name);
+ write_member_name (name);
+ write_template_args (TREE_OPERAND (member, 1));
+ }
+ else
+ write_expression (member);
+}
+
/* <expression> ::= <unary operator-name> <expression>
::= <binary operator-name> <expression> <expression>
::= <expr-primary>
<expr-primary> ::= <template-param>
::= L <type> <value number> E # literal
::= L <mangled-name> E # external name
- ::= sr <type> <unqualified-name>
+ ::= st <type> # sizeof
+ ::= sr <type> <unqualified-name> # dependent name
::= sr <type> <unqualified-name> <template-args> */
static void
write_expression (tree expr)
{
- enum tree_code code;
-
- code = TREE_CODE (expr);
+ enum tree_code code = TREE_CODE (expr);
/* Skip NOP_EXPRs. They can occur when (say) a pointer argument
is converted (via qualification conversions) to another
code = TREE_CODE (expr);
}
- if (code == BASELINK)
+ if (code == BASELINK
+ && (!type_unknown_p (expr)
+ || !BASELINK_QUALIFIED_P (expr)))
{
expr = BASELINK_FUNCTIONS (expr);
code = TREE_CODE (expr);
else if (TREE_CODE_CLASS (code) == tcc_constant
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (expr);
+ else if (code == PARM_DECL && DECL_ARTIFICIAL (expr))
+ {
+ gcc_assert (!strcmp ("this", IDENTIFIER_POINTER (DECL_NAME (expr))));
+ write_string ("fpT");
+ }
+ else if (code == PARM_DECL)
+ {
+ /* A function parameter used in a late-specified return type. */
+ int index = DECL_PARM_INDEX (expr);
+ int level = DECL_PARM_LEVEL (expr);
+ int delta = G.parm_depth - level + 1;
+ gcc_assert (index >= 1);
+ write_char ('f');
+ if (delta != 0)
+ {
+ if (abi_version_at_least (5))
+ {
+ /* Let L be the number of function prototype scopes from the
+ innermost one (in which the parameter reference occurs) up
+ to (and including) the one containing the declaration of
+ the referenced parameter. If the parameter declaration
+ clause of the innermost function prototype scope has been
+ completely seen, it is not counted (in that case -- which
+ is perhaps the most common -- L can be zero). */
+ write_char ('L');
+ write_unsigned_number (delta - 1);
+ }
+ else
+ G.need_abi_warning = true;
+ }
+ write_char ('p');
+ write_compact_number (index - 1);
+ }
else if (DECL_P (expr))
{
/* G++ 3.2 incorrectly mangled non-type template arguments of
write_string ("st");
write_type (TREE_OPERAND (expr, 0));
}
- else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
+ else if (TREE_CODE (expr) == ALIGNOF_EXPR
+ && TYPE_P (TREE_OPERAND (expr, 0)))
+ {
+ write_string ("at");
+ write_type (TREE_OPERAND (expr, 0));
+ }
+ else if (code == SCOPE_REF
+ || code == BASELINK)
{
- tree scope = TREE_OPERAND (expr, 0);
- tree member = TREE_OPERAND (expr, 1);
+ tree scope, member;
+ if (code == SCOPE_REF)
+ {
+ scope = TREE_OPERAND (expr, 0);
+ member = TREE_OPERAND (expr, 1);
+ }
+ else
+ {
+ scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (expr));
+ member = BASELINK_FUNCTIONS (expr);
+ }
+
+ if (!abi_version_at_least (2) && DECL_P (member))
+ {
+ write_string ("sr");
+ write_type (scope);
+ /* 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 (member);
+ }
/* 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))
+ else if (DECL_P (member))
write_expression (member);
else
{
- tree template_args;
-
write_string ("sr");
write_type (scope);
- /* If MEMBER is a template-id, separate the template
- from the arguments. */
- if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
- {
- template_args = TREE_OPERAND (member, 1);
- member = TREE_OPERAND (member, 0);
- }
- else
- template_args = NULL_TREE;
- /* Write out the name of the MEMBER. */
- if (IDENTIFIER_TYPENAME_P (member))
- write_conversion_operator_name (TREE_TYPE (member));
- else if (IDENTIFIER_OPNAME_P (member))
- {
- int i;
- const char *mangled_name = NULL;
-
- /* Unfortunately, there is no easy way to go from the
- name of the operator back to the corresponding tree
- code. */
- for (i = 0; i < LAST_CPLUS_TREE_CODE; ++i)
- if (operator_name_info[i].identifier == member)
- {
- /* The ABI says that we prefer binary operator
- names to unary operator names. */
- if (operator_name_info[i].arity == 2)
- {
- mangled_name = operator_name_info[i].mangled_name;
- break;
- }
- else if (!mangled_name)
- mangled_name = operator_name_info[i].mangled_name;
- }
- else if (assignment_operator_name_info[i].identifier
- == member)
- {
- mangled_name
- = assignment_operator_name_info[i].mangled_name;
- break;
- }
- write_string (mangled_name);
- }
- else
- write_source_name (member);
- /* Write out the template arguments. */
- if (template_args)
- write_template_args (template_args);
+ write_member_name (member);
+ }
+ }
+ else if (TREE_CODE (expr) == INDIRECT_REF
+ && TREE_TYPE (TREE_OPERAND (expr, 0))
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+ {
+ write_expression (TREE_OPERAND (expr, 0));
+ }
+ else if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ {
+ /* An operator name appearing as a dependent name needs to be
+ specially marked to disambiguate between a use of the operator
+ name and a use of the operator in an expression. */
+ if (IDENTIFIER_OPNAME_P (expr))
+ write_string ("on");
+ write_unqualified_id (expr);
+ }
+ else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+ {
+ tree fn = TREE_OPERAND (expr, 0);
+ if (is_overloaded_fn (fn))
+ fn = DECL_NAME (get_first_fn (fn));
+ if (IDENTIFIER_OPNAME_P (fn))
+ write_string ("on");
+ write_unqualified_id (fn);
+ write_template_args (TREE_OPERAND (expr, 1));
+ }
+ else if (TREE_CODE (expr) == MODOP_EXPR)
+ {
+ enum tree_code subop = TREE_CODE (TREE_OPERAND (expr, 1));
+ const char *name = (assignment_operator_name_info[(int) subop]
+ .mangled_name);
+ write_string (name);
+ write_expression (TREE_OPERAND (expr, 0));
+ write_expression (TREE_OPERAND (expr, 2));
+ }
+ else if (code == NEW_EXPR || code == VEC_NEW_EXPR)
+ {
+ /* ::= [gs] nw <expression>* _ <type> E
+ ::= [gs] nw <expression>* _ <type> <initializer>
+ ::= [gs] na <expression>* _ <type> E
+ ::= [gs] na <expression>* _ <type> <initializer>
+ <initializer> ::= pi <expression>* E */
+ tree placement = TREE_OPERAND (expr, 0);
+ tree type = TREE_OPERAND (expr, 1);
+ tree nelts = TREE_OPERAND (expr, 2);
+ tree init = TREE_OPERAND (expr, 3);
+ tree t;
+
+ gcc_assert (code == NEW_EXPR);
+ if (TREE_OPERAND (expr, 2))
+ code = VEC_NEW_EXPR;
+
+ if (NEW_EXPR_USE_GLOBAL (expr))
+ write_string ("gs");
+
+ write_string (operator_name_info[(int) code].mangled_name);
+
+ for (t = placement; t; t = TREE_CHAIN (t))
+ write_expression (TREE_VALUE (t));
+
+ write_char ('_');
+
+ if (nelts)
+ {
+ tree domain;
+ ++processing_template_decl;
+ domain = compute_array_index_type (NULL_TREE, nelts,
+ tf_warning_or_error);
+ type = build_cplus_array_type (type, domain);
+ --processing_template_decl;
+ }
+ write_type (type);
+
+ if (init && TREE_CODE (init) == TREE_LIST
+ && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
+ && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+ write_expression (TREE_VALUE (init));
+ else
+ {
+ if (init)
+ write_string ("pi");
+ if (init && init != void_zero_node)
+ for (t = init; t; t = TREE_CHAIN (t))
+ write_expression (TREE_VALUE (t));
+ write_char ('E');
+ }
+ }
+ else if (code == DELETE_EXPR || code == VEC_DELETE_EXPR)
+ {
+ gcc_assert (code == DELETE_EXPR);
+ if (DELETE_EXPR_USE_VEC (expr))
+ code = VEC_DELETE_EXPR;
+
+ if (DELETE_EXPR_USE_GLOBAL (expr))
+ write_string ("gs");
+
+ write_string (operator_name_info[(int) code].mangled_name);
+
+ write_expression (TREE_OPERAND (expr, 0));
+ }
+ else if (code == THROW_EXPR)
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (op)
+ {
+ write_string ("tw");
+ write_expression (op);
+ }
+ else
+ write_string ("tr");
+ }
+ else if (code == CONSTRUCTOR)
+ {
+ VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr);
+ unsigned i; tree val;
+
+ if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ write_string ("il");
+ else
+ {
+ write_string ("tl");
+ write_type (TREE_TYPE (expr));
}
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+ write_expression (val);
+ write_char ('E');
+ }
+ else if (dependent_name (expr))
+ {
+ write_unqualified_id (dependent_name (expr));
}
else
{
- int i;
+ int i, len;
+ const char *name;
/* 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 (code == COMPONENT_REF)
+ {
+ tree ob = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (ob) == ARROW_EXPR)
+ {
+ write_string (operator_name_info[(int)code].mangled_name);
+ ob = TREE_OPERAND (ob, 0);
+ }
+ else
+ write_string ("dt");
+
+ write_expression (ob);
+ write_member_name (TREE_OPERAND (expr, 1));
+ return;
+ }
+
/* If it wasn't any of those, recursively expand the expression. */
- write_string (operator_name_info[(int) code].mangled_name);
+ name = operator_name_info[(int) code].mangled_name;
+
+ /* We used to mangle const_cast and static_cast like a C cast. */
+ if (!abi_version_at_least (6)
+ && (code == CONST_CAST_EXPR
+ || code == STATIC_CAST_EXPR))
+ {
+ name = operator_name_info[CAST_EXPR].mangled_name;
+ G.need_abi_warning = 1;
+ }
+
+ if (name == NULL)
+ {
+ sorry ("mangling %C", code);
+ return;
+ }
+ else
+ write_string (name);
switch (code)
{
case CALL_EXPR:
- sorry ("call_expr cannot be mangled due to a defect in the C++ ABI");
+ {
+ tree fn = CALL_EXPR_FN (expr);
+
+ if (TREE_CODE (fn) == ADDR_EXPR)
+ fn = TREE_OPERAND (fn, 0);
+
+ /* Mangle a dependent name as the name, not whatever happens to
+ be the first function in the overload set. */
+ if ((TREE_CODE (fn) == FUNCTION_DECL
+ || TREE_CODE (fn) == OVERLOAD)
+ && type_dependent_expression_p_push (expr))
+ fn = DECL_NAME (get_first_fn (fn));
+
+ write_expression (fn);
+ }
+
+ for (i = 0; i < call_expr_nargs (expr); ++i)
+ write_expression (CALL_EXPR_ARG (expr, i));
+ write_char ('E');
break;
case CAST_EXPR:
write_type (TREE_TYPE (expr));
- /* There is no way to mangle a zero-operand cast like
- "T()". */
- if (!TREE_OPERAND (expr, 0))
- sorry ("zero-operand casts cannot be mangled due to a defect "
- "in the C++ ABI");
- else
+ if (list_length (TREE_OPERAND (expr, 0)) == 1)
write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
+ else
+ {
+ tree args = TREE_OPERAND (expr, 0);
+ write_char ('_');
+ for (; args; args = TREE_CHAIN (args))
+ write_expression (TREE_VALUE (args));
+ write_char ('E');
+ }
break;
+ case DYNAMIC_CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
case STATIC_CAST_EXPR:
case CONST_CAST_EXPR:
write_type (TREE_TYPE (expr));
write_expression (TREE_OPERAND (expr, 0));
break;
-
- /* Handle pointers-to-members specially. */
- case SCOPE_REF:
- write_type (TREE_OPERAND (expr, 0));
- if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
- write_source_name (TREE_OPERAND (expr, 1));
- else if (TREE_CODE (TREE_OPERAND (expr, 1)) == TEMPLATE_ID_EXPR)
- {
- tree template_id;
- tree name;
-
- template_id = TREE_OPERAND (expr, 1);
- name = TREE_OPERAND (template_id, 0);
- /* FIXME: What about operators? */
- gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
- write_source_name (TREE_OPERAND (template_id, 0));
- write_template_args (TREE_OPERAND (template_id, 1));
- }
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ if (abi_version_at_least (6))
+ write_char ('_');
else
- {
- /* G++ 3.2 incorrectly put out both the "sr" code and
- the nested name of the qualified name. */
- G.need_abi_warning = 1;
- write_encoding (TREE_OPERAND (expr, 1));
- }
- break;
+ G.need_abi_warning = 1;
+ /* Fall through. */
default:
- for (i = 0; i < TREE_OPERAND_LENGTH (expr); ++i)
+ /* In the middle-end, some expressions have more operands than
+ they do in templates (and mangling). */
+ len = cp_tree_operand_length (expr);
+
+ for (i = 0; i < len; ++i)
{
tree operand = TREE_OPERAND (expr, i);
/* As a GNU extension, the middle operand of a
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 a null member pointer value as (type)0, regardless of its
+ real representation. */
+ if (null_member_pointer_value_p (value))
+ write_integer_cst (integer_zero_node);
+ else
+ 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;
+
+ case COMPLEX_CST:
+ if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST
+ && TREE_CODE (TREE_IMAGPART (value)) == INTEGER_CST)
+ {
+ write_integer_cst (TREE_REALPART (value));
+ write_char ('_');
+ write_integer_cst (TREE_IMAGPART (value));
+ }
+ else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST
+ && TREE_CODE (TREE_IMAGPART (value)) == REAL_CST)
+ {
+ write_real_cst (TREE_REALPART (value));
+ write_char ('_');
+ write_real_cst (TREE_IMAGPART (value));
+ }
+ else
+ gcc_unreachable ();
+ break;
+
+ case STRING_CST:
+ sorry ("string literal in function template signature");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
write_char ('E');
}
G.need_abi_warning = 1;
}
+ if (TREE_CODE (node) == BASELINK
+ && !type_unknown_p (node))
+ {
+ if (abi_version_at_least (6))
+ node = BASELINK_FUNCTIONS (node);
+ else
+ /* We wrongly wrapped a class-scope function in X/E. */
+ G.need_abi_warning = 1;
+ }
+
if (ARGUMENT_PACK_P (node))
{
/* Expand the template argument pack. */
tree args = ARGUMENT_PACK_ARGS (node);
int i, length = TREE_VEC_LENGTH (args);
+ if (abi_version_at_least (6))
+ write_char ('J');
+ else
+ {
+ write_char ('I');
+ G.need_abi_warning = 1;
+ }
for (i = 0; i < length; ++i)
write_template_arg (TREE_VEC_ELT (args, i));
+ write_char ('E');
}
else if (TYPE_P (node))
write_type (node);
/* A template appearing as a template arg is a template template arg. */
write_template_template_arg (node);
else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
- || (abi_version_at_least (2) && code == CONST_DECL))
+ || (abi_version_at_least (2) && code == CONST_DECL)
+ || null_member_pointer_value_p (node))
write_template_arg_literal (node);
else if (DECL_P (node))
{
write_template_param (const tree parm)
{
int parm_index;
- int parm_level;
- tree parm_type = NULL_TREE;
MANGLE_TRACE_TREE ("template-parm", 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:
write_char ('T');
/* NUMBER as it appears in the mangling is (-1)-indexed, with the
earliest template param denoted by `_'. */
- if (parm_index > 0)
- write_unsigned_number (parm_index - 1);
- write_char ('_');
+ write_compact_number (parm_index);
}
/* <template-template-param>
static void
write_template_template_param (const tree parm)
{
- tree template = NULL_TREE;
+ tree templ = NULL_TREE;
/* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
template template parameter. The substitution candidate here is
only the template. */
if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
{
- template
+ templ
= TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
- if (find_substitution (template))
+ if (find_substitution (templ))
return;
}
/* <template-param> encodes only the template parameter position,
not its template arguments, which is fine here. */
write_template_param (parm);
- if (template)
- add_substitution (template);
+ if (templ)
+ add_substitution (templ);
}
/* Non-terminal <substitution>.
finish_mangling_internal (warn);
/* Don't obstack_finish here, and the next start_mangling will
remove the identifier. */
- return get_identifier ((const char *) name_base);
+ return get_identifier ((const char *) obstack_base (mangle_obstack));
}
/* Initialize data structures for mangling. */
mangle_decl_string (const tree decl)
{
tree result;
+ location_t saved_loc = input_location;
+ tree saved_fn = NULL_TREE;
+ bool template_p = false;
+
+ /* We shouldn't be trying to mangle an uninstantiated template. */
+ gcc_assert (!type_dependent_expression_p (decl));
+
+ if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
+ {
+ struct tinst_level *tl = current_instantiation ();
+ if ((!tl || tl->decl != decl)
+ && push_tinst_level (decl))
+ {
+ template_p = true;
+ saved_fn = current_function_decl;
+ current_function_decl = NULL_TREE;
+ }
+ }
+ input_location = DECL_SOURCE_LOCATION (decl);
start_mangling (decl);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
IDENTIFIER_POINTER (result));
+
+ if (template_p)
+ {
+ pop_tinst_level ();
+ current_function_decl = saved_fn;
+ }
+ input_location = saved_loc;
+
return result;
}
+/* Return an identifier for the external mangled name of DECL. */
+
+static tree
+get_mangled_id (tree decl)
+{
+ tree id = mangle_decl_string (decl);
+ return targetm.mangle_decl_assembler_name (decl, id);
+}
+
/* Create an identifier for the external mangled name of DECL. */
void
mangle_decl (const tree decl)
{
- tree id = mangle_decl_string (decl);
- id = targetm.mangle_decl_assembler_name (decl, id);
+ tree id;
+ bool dep;
+
+ /* Don't bother mangling uninstantiated templates. */
+ ++processing_template_decl;
+ if (TREE_CODE (decl) == TYPE_DECL)
+ dep = dependent_type_p (TREE_TYPE (decl));
+ else
+ dep = (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
+ && any_dependent_template_arguments_p (DECL_TI_ARGS (decl)));
+ --processing_template_decl;
+ if (dep)
+ return;
+
+ id = get_mangled_id (decl);
SET_DECL_ASSEMBLER_NAME (decl, id);
+
+ if (G.need_abi_warning
+ /* Don't do this for a fake symbol we aren't going to emit anyway. */
+ && !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
+ && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
+ {
+#ifdef ASM_OUTPUT_DEF
+ /* If the mangling will change in the future, emit an alias with the
+ future mangled name for forward-compatibility. */
+ int save_ver;
+ tree id2, alias;
+#endif
+
+ SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
+ if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
+ inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
+ "avoids this error with a change in mangling");
+
+#ifdef ASM_OUTPUT_DEF
+ save_ver = flag_abi_version;
+ flag_abi_version = 0;
+ id2 = mangle_decl_string (decl);
+ id2 = targetm.mangle_decl_assembler_name (decl, id2);
+ flag_abi_version = save_ver;
+
+ alias = make_alias_for (decl, id2);
+ DECL_IGNORED_P (alias) = 1;
+ TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
+ DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
+ if (vague_linkage_p (decl))
+ DECL_WEAK (alias) = 1;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ cgraph_same_body_alias (cgraph_get_create_node (decl), alias, decl);
+ else
+ varpool_extra_name_alias (alias, decl);
+#endif
+ }
}
/* Generate the mangled representation of TYPE. */
initialize a static reference. This isn't part of the ABI, but we might
as well call them something readable. */
+static GTY(()) int temp_count;
+
tree
mangle_ref_init_variable (const tree variable)
{
start_mangling (variable);
write_string ("_ZGR");
write_name (variable, /*ignore_local_scope=*/0);
+ /* Avoid name clashes with aggregate initialization of multiple
+ references at once. */
+ write_unsigned_number (temp_count++);
return finish_mangling_get_identifier (/*warn=*/false);
}
\f