/* Name mangling for the 3.0 C++ ABI.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
- 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_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)
}
}
+/* 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)
+{
+ 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>. */
/* 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);
else
{
/* No, just use <prefix> */
- write_prefix (DECL_CONTEXT (decl));
+ write_prefix (CP_DECL_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;
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);
<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
+ 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)
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ {
+ write_unqualified_id (decl);
+ return;
+ }
+
+ if (DECL_NAME (decl) == NULL_TREE)
{
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
write_source_name (DECL_ASSEMBLER_NAME (decl));
+ return;
}
- else if (DECL_CONV_FN_P (decl))
+ else if (DECL_DECLARES_FUNCTION_P (decl))
{
- /* Conversion operator. Handle it right here.
- <operator> ::= cv <type> */
- tree type;
- if (decl_is_template_id (decl, NULL))
+ 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))
{
- tree fn_type;
- fn_type = get_mostly_instantiated_function_type (decl);
- type = TREE_TYPE (fn_type);
+ /* 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
- 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;
+ 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));
}
+/* 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;
+ /* 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 (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
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;
break;
case DECLTYPE_TYPE:
+ /* These shouldn't make it into mangling. */
+ gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type)
+ && !DECLTYPE_FOR_LAMBDA_RETURN (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');
- ++skip_evaluation;
+ ++cp_unevaluated_operand;
write_expression (DECLTYPE_TYPE_EXPR (type));
- --skip_evaluation;
+ --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;
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;
{
/* 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_member_name (tree member)
{
if (TREE_CODE (member) == IDENTIFIER_NODE)
- write_source_name (member);
+ write_unqualified_id (member);
else if (DECL_P (member))
- {
- /* G++ 3.2 incorrectly put out both the "sr" code and
- the nested name of the qualified name. */
- G.need_abi_warning = 1;
- write_unqualified_name (member);
- }
+ write_unqualified_name (member);
else if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
{
tree name = TREE_OPERAND (member, 0);
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 = parm_index (expr);
- write_string ("fp");
- if (index > 1)
- write_unsigned_number (index - 2);
- write_char ('_');
+ 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))
{
write_string ("at");
write_type (TREE_OPERAND (expr, 0));
}
- else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
+ else if (TREE_CODE (expr) == SCOPE_REF)
{
tree scope = TREE_OPERAND (expr, 0);
tree member = TREE_OPERAND (expr, 1);
+ 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 < MAX_TREE_CODES; ++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
{
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
{
- int i;
+ int i, len;
const char *name;
/* When we bind a variable or function to a non-type template
&& type_dependent_expression_p_push (expr))
fn = DECL_NAME (get_first_fn (fn));
- if (TREE_CODE (fn) == IDENTIFIER_NODE)
- write_source_name (fn);
- else
- write_expression (fn);
+ write_expression (fn);
}
for (i = 0; i < call_expr_nargs (expr); ++i)
sorry ("mangling new-expression");
break;
- /* Handle pointers-to-members specially. */
- case SCOPE_REF:
- write_type (TREE_OPERAND (expr, 0));
- write_member_name (TREE_OPERAND (expr, 1));
- break;
-
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_real_cst (value);
break;
+ case STRING_CST:
+ sorry ("string literal in function template signature");
+ break;
+
default:
gcc_unreachable ();
}
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>
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;
}
tree id = mangle_decl_string (decl);
id = targetm.mangle_decl_assembler_name (decl, id);
SET_DECL_ASSEMBLER_NAME (decl, id);
+
+ if (G.need_abi_warning)
+ {
+#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=4 (or =0) "
+ "avoids this error with a change in vector 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. */