/* Name mangling for the 3.0 C++ ABI.
- Copyright (C) 2000-2013 Free Software Foundation, Inc.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com>
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
+#include "tree-hasher.h"
+#include "stor-layout.h"
+#include "stringpool.h"
#include "tm_p.h"
#include "cp-tree.h"
#include "obstack.h"
#include "flags.h"
#include "target.h"
#include "cgraph.h"
+#include "wide-int.h"
/* Debugging support. */
fprintf (stderr, " %-24s: %-24s\n", (FN), (INPUT))
# define MANGLE_TRACE_TREE(FN, NODE) \
fprintf (stderr, " %-24s: %-24s (%p)\n", \
- (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
+ (FN), get_tree_code_name (TREE_CODE (NODE)), (void *) (NODE))
#else
# define MANGLE_TRACE(FN, INPUT)
# define MANGLE_TRACE_TREE(FN, NODE)
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_unqualified_name (tree);
static void write_conversion_operator_name (const tree);
static void write_source_name (tree);
static void write_literal_operator_name (tree);
/* Control functions. */
static inline void start_mangling (const tree);
-static inline const char *finish_mangling (const bool);
static tree mangle_special_for_type (const tree, const char *);
/* Foreign language functions. */
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)));
+ name = TYPE_NAME_STRING (el);
fprintf (stderr, " S%d_ = ", i - 1);
if (TYPE_P (el) &&
(CP_TYPE_RESTRICT_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);
+ name, get_tree_code_name (TREE_CODE (el)), (void *) el);
}
}
&& TYPE_CANONICAL (node) != node
&& TYPE_MAIN_VARIANT (node) != node)
{
+ tree orig = node;
/* Here we want to strip the topmost typedef only.
We need to do that so is_std_substitution can do proper
name matching. */
else
node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
cp_type_quals (node));
+ if (TREE_CODE (node) == FUNCTION_TYPE
+ || TREE_CODE (node) == METHOD_TYPE)
+ node = build_ref_qualified_type (node, type_memfn_rqual (orig));
}
return node;
}
if (DEBUG_MANGLE)
fprintf (stderr, " ++ add_substitution (%s at %10p)\n",
- tree_code_name[TREE_CODE (node)], (void *) node);
+ get_tree_code_name (TREE_CODE (node)), (void *) node);
/* Get the canonicalized substitution candidate for NODE. */
c = canonicalize_for_substitution (node);
if (DEBUG_MANGLE && c != node)
fprintf (stderr, " ++ using candidate (%s at %10p)\n",
- tree_code_name[TREE_CODE (node)], (void *) node);
+ get_tree_code_name (TREE_CODE (node)), (void *) node);
node = c;
#if ENABLE_CHECKING
const int size = vec_safe_length (G.substitutions);
tree decl;
tree type;
+ const char *abbr = NULL;
if (DEBUG_MANGLE)
fprintf (stderr, " ++ find_substitution (%s at %p)\n",
- tree_code_name[TREE_CODE (node)], (void *) node);
+ get_tree_code_name (TREE_CODE (node)), (void *) node);
/* Obtain the canonicalized substitution representation for NODE.
This is what we'll compare against. */
if (decl
&& is_std_substitution (decl, SUBID_ALLOCATOR)
&& !CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)))
- {
- write_string ("Sa");
- return 1;
- }
+ abbr = "Sa";
/* Check for std::basic_string. */
- if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
+ else if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
{
if (TYPE_P (node))
{
SUBID_CHAR_TRAITS)
&& is_std_substitution_char (TREE_VEC_ELT (args, 2),
SUBID_ALLOCATOR))
- {
- write_string ("Ss");
- return 1;
- }
+ abbr = "Ss";
}
}
else
/* Substitute for the template name only if this isn't a type. */
- {
- write_string ("Sb");
- return 1;
- }
+ abbr = "Sb";
}
/* Check for basic_{i,o,io}stream. */
- if (TYPE_P (node)
- && cp_type_quals (type) == TYPE_UNQUALIFIED
- && CLASS_TYPE_P (type)
- && CLASSTYPE_USE_TEMPLATE (type)
- && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
+ else if (TYPE_P (node)
+ && cp_type_quals (type) == TYPE_UNQUALIFIED
+ && CLASS_TYPE_P (type)
+ && CLASSTYPE_USE_TEMPLATE (type)
+ && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
{
/* First, check for the template
args <char, std::char_traits<char> > . */
{
/* Got them. Is this basic_istream? */
if (is_std_substitution (decl, SUBID_BASIC_ISTREAM))
- {
- write_string ("Si");
- return 1;
- }
+ abbr = "Si";
/* Or basic_ostream? */
else if (is_std_substitution (decl, SUBID_BASIC_OSTREAM))
- {
- write_string ("So");
- return 1;
- }
+ abbr = "So";
/* Or basic_iostream? */
else if (is_std_substitution (decl, SUBID_BASIC_IOSTREAM))
- {
- write_string ("Sd");
- return 1;
- }
+ abbr = "Sd";
}
}
/* Check for namespace std. */
- if (decl && DECL_NAMESPACE_STD_P (decl))
+ else if (decl && DECL_NAMESPACE_STD_P (decl))
{
write_string ("St");
return 1;
}
+ tree tags = NULL_TREE;
+ if (OVERLOAD_TYPE_P (node))
+ tags = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (type));
/* Now check the list of available substitutions for this mangling
operation. */
- for (i = 0; i < size; ++i)
+ if (!abbr || tags) for (i = 0; i < size; ++i)
{
tree candidate = (*G.substitutions)[i];
/* NODE is a matched to a candidate if it's the same decl node or
}
}
- /* No substitution found. */
- return 0;
+ if (!abbr)
+ /* No substitution found. */
+ return 0;
+
+ write_string (abbr);
+ if (tags)
+ {
+ /* If there are ABI tags on the abbreviation, it becomes
+ a substitution candidate. */
+ write_abi_tags (tags);
+ add_substitution (node);
+ }
+ return 1;
}
<source-name> without a type." We cannot write
overloaded operators that way though, because it contains
characters invalid in assembler. */
- if (abi_version_at_least (2))
- write_string ("_Z");
- else
- G.need_abi_warning = true;
+ write_string ("_Z");
write_source_name (DECL_NAME (decl));
}
}
- else if (TREE_CODE (decl) == VAR_DECL
+ else if (VAR_P (decl)
+ /* Variable template instantiations are mangled. */
+ && !(DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
/* The names of non-static global variables aren't mangled. */
&& DECL_EXTERNAL_LINKAGE_P (decl)
&& (CP_DECL_CONTEXT (decl) == global_namespace
/* And neither are `extern "C"' variables. */
|| DECL_EXTERN_C_P (decl)))
{
- if (top_level || abi_version_at_least (2))
- goto unmangled_name;
- else
- {
- G.need_abi_warning = true;
- goto mangled_name;
- }
+ goto unmangled_name;
}
else
{
- mangled_name:;
write_string ("_Z");
write_encoding (decl);
- if (DECL_LANG_SPECIFIC (decl)
- && (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
- || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)))
- /* We need a distinct mangled name for these entities, but
- we should never actually output it. So, we append some
- characters the assembler won't like. */
- write_string (" *INTERNAL* ");
}
}
if (tcontext != NULL_TREE)
return tcontext;
+ if (TREE_CODE (decl) == TEMPLATE_DECL
+ && DECL_TEMPLATE_RESULT (decl))
+ decl = DECL_TEMPLATE_RESULT (decl);
+
if (TREE_CODE (decl) == TYPE_DECL
&& LAMBDA_TYPE_P (TREE_TYPE (decl)))
{
context = decl_mangling_context (decl);
+ gcc_assert (context != NULL_TREE);
+
+ if (abi_version_crosses (7)
+ && ignore_local_scope
+ && TREE_CODE (context) == PARM_DECL)
+ G.need_abi_warning = 1;
+
/* A decl in :: or ::std scope is treated specially. The former is
mangled using <unscoped-name> or <unscoped-template-name>, the
latter with a special substitution. Also, a name that is
directly in a local function scope is also mangled with
<unscoped-name> rather than a full <nested-name>. */
- if (context == NULL
- || context == global_namespace
+ if (context == global_namespace
|| DECL_NAMESPACE_STD_P (context)
|| (ignore_local_scope
&& (TREE_CODE (context) == FUNCTION_DECL
directly in that function's scope, either decl or one of
its enclosing scopes. */
tree local_entity = decl;
- while (context != NULL && context != global_namespace)
+ while (context != global_namespace)
{
/* Make sure we're always dealing with decls. */
- if (context != NULL && TYPE_P (context))
+ if (TYPE_P (context))
context = TYPE_NAME (context);
/* Is this a function? */
if (TREE_CODE (context) == FUNCTION_DECL
else
{
/* If not, it should be either in the global namespace, or directly
- in a local function scope. */
+ in a local function scope. A lambda can also be mangled in the
+ scope of a default argument. */
gcc_assert (context == global_namespace
- || context != NULL
+ || TREE_CODE (context) == PARM_DECL
|| TREE_CODE (context) == FUNCTION_DECL);
write_unqualified_name (decl);
/* Write the nested name, including CV-qualifiers, of DECL.
- <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
- ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+ <ref-qualifier> ::= R # & ref-qualifier
+ ::= O # && ref-qualifier
<CV-qualifiers> ::= [r] [V] [K] */
static void
write_char ('V');
if (DECL_CONST_MEMFUNC_P (decl))
write_char ('K');
+ if (FUNCTION_REF_QUALIFIED (TREE_TYPE (decl)))
+ {
+ if (FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl)))
+ write_char ('O');
+ else
+ write_char ('R');
+ }
}
/* Is this a template instance? */
template_info = TYPE_TEMPLATE_INFO (node);
}
- /* In G++ 3.2, the name of the template parameter was used. */
- if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
- && !abi_version_at_least (2))
- G.need_abi_warning = true;
-
- if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
- && abi_version_at_least (2))
+ if (TREE_CODE (node) == TEMPLATE_TYPE_PARM)
write_template_param (node);
else if (template_info != NULL)
/* Templated. */
{
write_prefix (decl_mangling_context (decl));
write_unqualified_name (decl);
- if (TREE_CODE (decl) == VAR_DECL
+ if (VAR_P (decl)
|| TREE_CODE (decl) == FIELD_DECL)
{
/* <data-member-prefix> := <member source-name> M */
if (find_substitution (substitution))
return;
- /* In G++ 3.2, the name of the template template parameter was used. */
- if (TREE_TYPE (templ)
- && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
- && !abi_version_at_least (2))
- G.need_abi_warning = true;
-
if (TREE_TYPE (templ)
- && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
- && abi_version_at_least (2))
+ && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM)
write_template_param (TREE_TYPE (templ));
else
{
}
static void
-write_unqualified_name (const tree decl)
+write_unqualified_name (tree decl)
{
MANGLE_TRACE_TREE ("unqualified-name", decl);
- if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ if (identifier_p (decl))
{
write_unqualified_id (decl);
return;
fn_type = get_mostly_instantiated_function_type (decl);
type = TREE_TYPE (fn_type);
}
+ else if (FNDECL_USED_AUTO (decl))
+ type = (DECL_STRUCT_FUNCTION (decl)->language
+ ->x_auto_return_pattern);
else
type = DECL_CONV_FN_TYPE (decl);
write_conversion_operator_name (type);
write_source_name (DECL_NAME (decl));
}
- tree attrs = (TREE_CODE (decl) == TYPE_DECL
- ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
- : DECL_ATTRIBUTES (decl));
- write_abi_tags (lookup_attribute ("abi_tag", attrs));
+ /* We use the ABI tags from the primary template, ignoring tags on any
+ specializations. This is necessary because C++ doesn't require a
+ specialization to be declared before it is used unless the use
+ requires a complete type, but we need to get the tags right on
+ incomplete types as well. */
+ if (tree tmpl = most_general_template (decl))
+ decl = DECL_TEMPLATE_RESULT (tmpl);
+ /* Don't crash on an unbound class template. */
+ if (decl)
+ {
+ tree attrs = (TREE_CODE (decl) == TYPE_DECL
+ ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
+ : DECL_ATTRIBUTES (decl));
+ write_abi_tags (lookup_attribute ("abi_tag", attrs));
+ }
}
/* Write the unqualified-name for a conversion operator to TYPE. */
for (tree t = tags; t; t = TREE_CHAIN (t))
{
+ if (ABI_TAG_IMPLICIT (t))
+ continue;
tree str = TREE_VALUE (t);
vec_safe_push (vec, str);
}
/* Convert NUMBER to ascii using base BASE and generating at least
MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
into which to store the characters. Returns the number of
- characters generated (these will be layed out in advance of where
+ characters generated (these will be laid out in advance of where
BUFFER points). */
static int
write_integer_cst (const tree cst)
{
int sign = tree_int_cst_sgn (cst);
-
- if (TREE_INT_CST_HIGH (cst) + (sign < 0))
+ widest_int abs_value = wi::abs (wi::to_widest (cst));
+ if (!wi::fits_uhwi_p (abs_value))
{
/* A bignum. We do this in chunks, each of which fits in a
HOST_WIDE_INT. */
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));
+ n = wide_int_to_tree (type, cst);
if (sign < 0)
{
else
{
/* A small num. */
- unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
-
if (sign < 0)
- {
- write_char ('n');
- low = -low;
- }
- write_unsigned_number (low);
+ write_char ('n');
+ write_unsigned_number (abs_value.to_uhwi ());
}
}
static void
write_real_cst (const tree value)
{
- if (abi_version_at_least (2))
- {
- long target_real[4]; /* largest supported float */
- char buffer[9]; /* eight hex digits in a 32-bit number */
- int i, limit, dir;
+ long target_real[4]; /* largest supported float */
+ char buffer[9]; /* eight hex digits in a 32-bit number */
+ int i, limit, dir;
- tree type = TREE_TYPE (value);
- int words = GET_MODE_BITSIZE (TYPE_MODE (type)) / 32;
+ 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));
+ real_to_target (target_real, &TREE_REAL_CST (value),
+ TYPE_MODE (type));
- /* The value in target_real is in the target word order,
- so we must write it out backward if that happens to be
- little-endian. write_number cannot be used, it will
- produce uppercase. */
- if (FLOAT_WORDS_BIG_ENDIAN)
- i = 0, limit = words, dir = 1;
- else
- i = words - 1, limit = -1, dir = -1;
-
- for (; i != limit; i += dir)
- {
- sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
- write_chars (buffer, 8);
- }
- }
+ /* The value in target_real is in the target word order,
+ so we must write it out backward if that happens to be
+ little-endian. write_number cannot be used, it will
+ produce uppercase. */
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ i = 0, limit = words, dir = 1;
else
+ i = words - 1, limit = -1, dir = -1;
+
+ for (; i != limit; i += dir)
{
- /* In G++ 3.3 and before the REAL_VALUE_TYPE was written out
- literally. Note that compatibility with 3.2 is impossible,
- because the old floating-point emulator used a different
- format for REAL_VALUE_TYPE. */
- size_t i;
- for (i = 0; i < sizeof (TREE_REAL_CST (value)); ++i)
- write_number (((unsigned char *) &TREE_REAL_CST (value))[i],
- /*unsigned_p*/ 1,
- /*base*/ 16);
- G.need_abi_warning = 1;
+ sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
+ write_chars (buffer, 8);
}
}
::= C2 # base object constructor
::= C3 # complete object allocating constructor
- Currently, allocating constructors are never used.
-
- We also need to provide mangled names for the maybe-in-charge
- constructor, so we treat it here too. mangle_decl_string will
- append *INTERNAL* to that, to make sure we never emit it. */
+ Currently, allocating constructors are never used. */
static void
write_special_name_constructor (const tree ctor)
{
if (DECL_BASE_CONSTRUCTOR_P (ctor))
write_string ("C2");
+ /* This is the old-style "[unified]" constructor.
+ In some cases, we may emit this function and call
+ it from the clones in order to share code and save space. */
+ else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
+ write_string ("C4");
else
{
- gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
- /* Even though we don't ever emit a definition of
- the old-style destructor, we still have to
- consider entities (like static variables) nested
- inside it. */
- || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor));
+ gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor));
write_string ("C1");
}
}
<special-name> ::= D0 # deleting (in-charge) destructor
::= D1 # complete object (in-charge) destructor
- ::= D2 # base object (not-in-charge) destructor
-
- We also need to provide mangled names for the maybe-incharge
- destructor, so we treat it here too. mangle_decl_string will
- append *INTERNAL* to that, to make sure we never emit it. */
+ ::= D2 # base object (not-in-charge) destructor */
static void
write_special_name_destructor (const tree dtor)
write_string ("D0");
else if (DECL_BASE_DESTRUCTOR_P (dtor))
write_string ("D2");
+ else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
+ /* This is the old-style "[unified]" destructor.
+ In some cases, we may emit this function and call
+ it from the clones in order to share code and save space. */
+ write_string ("D4");
else
{
- gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor)
- /* Even though we don't ever emit a definition of
- the old-style destructor, we still have to
- consider entities (like static variables) nested
- inside it. */
- || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor));
+ gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor));
write_string ("D1");
}
}
mangle the unqualified type. The recursive call is needed here
since both the qualified and unqualified types are substitution
candidates. */
- write_type (TYPE_MAIN_VARIANT (type));
+ {
+ tree t = TYPE_MAIN_VARIANT (type);
+ if (TREE_CODE (t) == FUNCTION_TYPE
+ || TREE_CODE (t) == METHOD_TYPE)
+ {
+ t = build_ref_qualified_type (t, type_memfn_rqual (type));
+ if (abi_version_at_least (8))
+ /* Avoid adding the unqualified function type as a substitution. */
+ write_function_type (t);
+ else
+ write_type (t);
+ if (abi_version_crosses (8))
+ G.need_abi_warning = 1;
+ }
+ else
+ write_type (t);
+ }
else if (TREE_CODE (type) == ARRAY_TYPE)
/* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
so that the cv-qualification of the element type is available
/* See through any typedefs. */
type = TYPE_MAIN_VARIANT (type);
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
/* According to the C++ ABI, some library classes are passed the
same as the scalar type of their single member and use the same
write_string (target_mangling);
/* Add substitutions for types other than fundamental
types. */
- if (TREE_CODE (type) != VOID_TYPE
+ if (!VOID_TYPE_P (type)
&& TREE_CODE (type) != INTEGER_TYPE
&& TREE_CODE (type) != REAL_TYPE
&& TREE_CODE (type) != BOOLEAN_TYPE)
case POINTER_TYPE:
case REFERENCE_TYPE:
- if (TREE_CODE (type) == POINTER_TYPE)
+ if (TYPE_PTR_P (type))
write_char ('P');
else if (TYPE_REF_IS_RVALUE (type))
write_char ('O');
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);
+ if (TREE_CODE (target) == FUNCTION_TYPE)
+ {
+ if (abi_version_crosses (5)
+ && TYPE_QUALS (target) != TYPE_UNQUALIFIED)
+ G.need_abi_warning = 1;
+ if (abi_version_at_least (5))
+ target = build_qualified_type (target, TYPE_UNQUALIFIED);
+ }
write_type (target);
}
break;
case TEMPLATE_TYPE_PARM:
if (is_auto (type))
{
- write_identifier ("Da");
+ if (AUTO_IS_DECLTYPE (type))
+ write_identifier ("Dc");
+ else
+ write_identifier ("Da");
++is_builtin_type;
break;
}
write_char ('_');
}
else
- {
- G.need_abi_warning = 1;
- write_string ("U8__vector");
- }
+ write_string ("U8__vector");
+ if (abi_version_crosses (4))
+ G.need_abi_warning = 1;
write_type (TREE_TYPE (type));
break;
&& !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))
+ if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
{
tree expr = DECLTYPE_TYPE_EXPR (type);
tree etype = NULL_TREE;
if (etype && !type_uses_auto (etype))
{
- G.need_abi_warning = 1;
- write_type (etype);
- return;
+ if (abi_version_crosses (5))
+ G.need_abi_warning = 1;
+ if (!abi_version_at_least (5))
+ {
+ write_type (etype);
+ return;
+ }
}
}
write_string ("Dn");
if (abi_version_at_least (7))
++is_builtin_type;
+ if (abi_version_crosses (7))
+ G.need_abi_warning = 1;
break;
case TYPEOF_TYPE:
METHOD_TYPE. The return type is mangled before the parameter
types.
- <function-type> ::= F [Y] <bare-function-type> E */
+ <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
static void
write_function_type (const tree type)
See [dcl.link]. */
write_bare_function_type (type, /*include_return_type_p=*/1,
/*decl=*/NULL);
+ if (FUNCTION_REF_QUALIFIED (type))
+ {
+ if (FUNCTION_RVALUE_QUALIFIED (type))
+ write_char ('O');
+ else
+ write_char ('R');
+ }
write_char ('E');
}
static void
write_member_name (tree member)
{
- if (TREE_CODE (member) == IDENTIFIER_NODE)
+ if (identifier_p (member))
write_unqualified_id (member);
else if (DECL_P (member))
write_unqualified_name (member);
is converted (via qualification conversions) to another
type. */
while (TREE_CODE (expr) == NOP_EXPR
+ /* Parentheses aren't mangled. */
+ || code == PAREN_EXPR
|| TREE_CODE (expr) == NON_LVALUE_EXPR)
{
expr = TREE_OPERAND (expr, 0);
write_template_param (expr);
/* Handle literals. */
else if (TREE_CODE_CLASS (code) == tcc_constant
- || (abi_version_at_least (2) && code == CONST_DECL))
+ || code == CONST_DECL)
write_template_arg_literal (expr);
else if (code == PARM_DECL && DECL_ARTIFICIAL (expr))
{
write_char ('L');
write_unsigned_number (delta - 1);
}
- else
+ if (abi_version_crosses (5))
G.need_abi_warning = true;
}
write_char ('p');
}
else if (DECL_P (expr))
{
- /* G++ 3.2 incorrectly mangled non-type template arguments of
- enumeration type using their names. */
- if (code == CONST_DECL)
- G.need_abi_warning = 1;
write_char ('L');
write_mangled_name (expr, false);
write_char ('E');
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. */
- else if (DECL_P (member))
+ if (DECL_P (member))
write_expression (member);
else
{
write_member_name (member);
}
}
- else if (TREE_CODE (expr) == INDIRECT_REF
+ else if (INDIRECT_REF_P (expr)
&& 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)
+ else if (identifier_p (expr))
{
/* An operator name appearing as a dependent name needs to be
specially marked to disambiguate between a use of the operator
write_type (type);
if (init && TREE_CODE (init) == TREE_LIST
- && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
- && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+ && DIRECT_LIST_INIT_P (TREE_VALUE (init)))
write_expression (TREE_VALUE (init));
else
{
if (init)
write_string ("pi");
- if (init && init != void_zero_node)
+ if (init && init != void_node)
for (t = init; t; t = TREE_CHAIN (t))
write_expression (TREE_VALUE (t));
write_char ('E');
{
write_string (operator_name_info[(int)code].mangled_name);
ob = TREE_OPERAND (ob, 0);
+ write_expression (ob);
}
- else
- write_string ("dt");
+ else if (!is_dummy_object (ob))
+ {
+ write_string ("dt");
+ write_expression (ob);
+ }
+ /* else, for a non-static data member with no associated object (in
+ unevaluated context), use the unresolved-name mangling. */
- write_expression (ob);
write_member_name (TREE_OPERAND (expr, 1));
return;
}
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))
+ if (code == CONST_CAST_EXPR
+ || code == STATIC_CAST_EXPR)
{
- name = operator_name_info[CAST_EXPR].mangled_name;
- G.need_abi_warning = 1;
+ if (abi_version_crosses (6))
+ G.need_abi_warning = 1;
+ if (!abi_version_at_least (6))
+ name = operator_name_info[CAST_EXPR].mangled_name;
}
if (name == NULL)
case PREDECREMENT_EXPR:
if (abi_version_at_least (6))
write_char ('_');
- else
+ if (abi_version_crosses (6))
G.need_abi_warning = 1;
/* Fall through. */
internal consistency, such arguments use a conversion from
address of object to reference type. */
gcc_assert (TREE_CODE (TREE_OPERAND (node, 0)) == ADDR_EXPR);
- if (abi_version_at_least (2))
- node = TREE_OPERAND (TREE_OPERAND (node, 0), 0);
- else
- G.need_abi_warning = 1;
+ node = TREE_OPERAND (TREE_OPERAND (node, 0), 0);
}
if (TREE_CODE (node) == BASELINK
{
if (abi_version_at_least (6))
node = BASELINK_FUNCTIONS (node);
- else
+ if (abi_version_crosses (6))
/* We wrongly wrapped a class-scope function in X/E. */
G.need_abi_warning = 1;
}
if (abi_version_at_least (6))
write_char ('J');
else
- {
- write_char ('I');
- G.need_abi_warning = 1;
- }
+ write_char ('I');
+ if (abi_version_crosses (6))
+ G.need_abi_warning = 1;
for (i = 0; i < length; ++i)
write_template_arg (TREE_VEC_ELT (args, i));
write_char ('E');
/* 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)
+ || code == CONST_DECL
|| null_member_pointer_value_p (node))
write_template_arg_literal (node);
else if (DECL_P (node))
{
- /* Until ABI version 2, non-type template arguments of
- enumeration type were mangled using their names. */
- if (code == CONST_DECL && !abi_version_at_least (2))
- G.need_abi_warning = 1;
write_char ('L');
/* Until ABI version 3, the underscore before the mangled name
was incorrectly omitted. */
if (!abi_version_at_least (3))
- {
- G.need_abi_warning = 1;
- write_char ('Z');
- }
+ write_char ('Z');
else
write_string ("_Z");
+ if (abi_version_crosses (3))
+ G.need_abi_warning = 1;
write_encoding (node);
write_char ('E');
}
{
/* The ABI specifies that we should mangle the number of
elements in the array, not the largest allowed index. */
- double_int dmax = tree_to_double_int (max) + double_int_one;
+ offset_int wmax = wi::to_offset (max) + 1;
/* Truncate the result - this will mangle [0, SIZE_INT_MAX]
number of elements as zero. */
- dmax = dmax.zext (TYPE_PRECISION (TREE_TYPE (max)));
- gcc_assert (dmax.fits_uhwi ());
- write_unsigned_number (dmax.low);
+ wmax = wi::zext (wmax, TYPE_PRECISION (TREE_TYPE (max)));
+ gcc_assert (wi::fits_uhwi_p (wmax));
+ write_unsigned_number (wmax.to_uhwi ());
}
else
{
max = TREE_OPERAND (max, 0);
- if (!abi_version_at_least (2))
- {
- /* value_dependent_expression_p presumes nothing is
- dependent when PROCESSING_TEMPLATE_DECL is zero. */
- ++processing_template_decl;
- if (!value_dependent_expression_p (max))
- G.need_abi_warning = 1;
- --processing_template_decl;
- }
write_expression (max);
}
warning. */
static void
-finish_mangling_internal (const bool warn)
+finish_mangling_internal (void)
{
- if (warn_abi && warn && G.need_abi_warning)
- warning (OPT_Wabi, "the mangled name of %qD will change in a future "
- "version of GCC",
- G.entity);
-
/* Clear all the substitutions. */
vec_safe_truncate (G.substitutions, 0);
/* Like finish_mangling_internal, but return the mangled string. */
static inline const char *
-finish_mangling (const bool warn)
+finish_mangling (void)
{
- finish_mangling_internal (warn);
+ finish_mangling_internal ();
return (const char *) obstack_finish (mangle_obstack);
}
/* Like finish_mangling_internal, but return an identifier. */
static tree
-finish_mangling_get_identifier (const bool warn)
+finish_mangling_get_identifier (void)
{
- finish_mangling_internal (warn);
+ finish_mangling_internal ();
/* Don't obstack_finish here, and the next start_mangling will
remove the identifier. */
return get_identifier ((const char *) obstack_base (mangle_obstack));
else
write_mangled_name (decl, true);
- result = finish_mangling_get_identifier (/*warn=*/true);
+ result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
IDENTIFIER_POINTER (result));
if (G.need_abi_warning
/* Don't do this for a fake symbol we aren't going to emit anyway. */
+ && TREE_CODE (decl) != TYPE_DECL
&& !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
+ tree id2;
SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
- inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
+ inform (DECL_SOURCE_LOCATION (decl), "a later -fabi-version= (or =0) "
"avoids this error with a change in mangling");
-#ifdef ASM_OUTPUT_DEF
save_ver = flag_abi_version;
- flag_abi_version = 0;
+ flag_abi_version = flag_abi_compat_version;
id2 = mangle_decl_string (decl);
id2 = targetm.mangle_decl_assembler_name (decl, id2);
flag_abi_version = save_ver;
- alias = make_alias_for (decl, id2);
+ if (id2 == id)
+ return;
+
+ if (warn_abi)
+ {
+ if (flag_abi_compat_version != 0
+ && abi_version_at_least (flag_abi_compat_version))
+ warning (OPT_Wabi, "the mangled name of %q+D changed between "
+ "-fabi-version=%d (%D) and -fabi-version=%d (%D)",
+ G.entity, flag_abi_compat_version, id2,
+ flag_abi_version, id);
+ else
+ warning (OPT_Wabi, "the mangled name of %q+D changes between "
+ "-fabi-version=%d (%D) and -fabi-version=%d (%D)",
+ G.entity, flag_abi_version, id,
+ flag_abi_compat_version, id2);
+ }
+
+#ifdef ASM_OUTPUT_DEF
+ if (flag_abi_compat_version != 0
+ && IDENTIFIER_GLOBAL_VALUE (id2))
+ return;
+
+ tree alias = make_alias_for (decl, id2);
+ SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
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);
+ {
+ /* Don't create an alias to an unreferenced function. */
+ if (struct cgraph_node *n = cgraph_node::get (decl))
+ n->create_same_body_alias (alias, decl);
+ }
else
- varpool_extra_name_alias (alias, decl);
+ varpool_node::create_extra_name_alias (alias, decl);
#endif
}
}
start_mangling (type);
write_type (type);
- result = finish_mangling (/*warn=*/false);
+ result = finish_mangling ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
return result;
/* Add the type. */
write_type (type);
- result = finish_mangling_get_identifier (/*warn=*/false);
+ result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n",
write_char ('_');
write_type (BINFO_TYPE (binfo));
- result = finish_mangling_get_identifier (/*warn=*/false);
+ result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
IDENTIFIER_POINTER (result));
/* Scoped name. */
write_encoding (fn_decl);
- result = finish_mangling_get_identifier (/*warn=*/false);
+ result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
return result;
}
+struct conv_type_hasher : ggc_hasher<tree>
+{
+ static hashval_t hash (tree);
+ static bool equal (tree, tree);
+};
+
/* This hash table maps TYPEs to the IDENTIFIER for a conversion
operator to TYPE. The nodes are IDENTIFIERs whose TREE_TYPE is the
TYPE. */
-static GTY ((param_is (union tree_node))) htab_t conv_type_names;
+static GTY (()) hash_table<conv_type_hasher> *conv_type_names;
/* Hash a node (VAL1) in the table. */
-static hashval_t
-hash_type (const void *val)
+hashval_t
+conv_type_hasher::hash (tree val)
{
- return (hashval_t) TYPE_UID (TREE_TYPE ((const_tree) val));
+ return (hashval_t) TYPE_UID (TREE_TYPE (val));
}
/* Compare VAL1 (a node in the table) with VAL2 (a TYPE). */
-static int
-compare_type (const void *val1, const void *val2)
+bool
+conv_type_hasher::equal (tree val1, tree val2)
{
- return TREE_TYPE ((const_tree) val1) == (const_tree) val2;
+ return TREE_TYPE (val1) == val2;
}
/* Return an identifier for the mangled unqualified name for a
tree
mangle_conv_op_name_for_type (const tree type)
{
- void **slot;
+ tree *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);
+ conv_type_names = hash_table<conv_type_hasher>::create_ggc (31);
- slot = htab_find_slot_with_hash (conv_type_names, type,
- (hashval_t) TYPE_UID (type), INSERT);
- identifier = (tree)*slot;
+ slot = conv_type_names->find_slot_with_hash (type,
+ (hashval_t) TYPE_UID (type),
+ INSERT);
+ identifier = *slot;
if (!identifier)
{
char buffer[64];
/* Create a unique name corresponding to TYPE. */
- sprintf (buffer, "operator %lu",
- (unsigned long) htab_elements (conv_type_names));
+ sprintf (buffer, "operator %lu", conv_type_names->elements ());
identifier = get_identifier (buffer);
*slot = identifier;
static void
write_guarded_var_name (const tree variable)
{
- if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
+ if (DECL_NAME (variable)
+ && strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
/* The name of a guard variable for a reference temporary should refer
to the reference, not the temporary. */
write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
start_mangling (variable);
write_string ("_ZGV");
write_guarded_var_name (variable);
- return finish_mangling_get_identifier (/*warn=*/false);
+ return finish_mangling_get_identifier ();
}
/* Return an identifier for the name of a thread_local initialization
start_mangling (variable);
write_string ("_ZTH");
write_guarded_var_name (variable);
- return finish_mangling_get_identifier (/*warn=*/false);
+ return finish_mangling_get_identifier ();
}
/* Return an identifier for the name of a thread_local wrapper
start_mangling (variable);
write_string (TLS_WRAPPER_PREFIX);
write_guarded_var_name (variable);
- return finish_mangling_get_identifier (/*warn=*/false);
+ return finish_mangling_get_identifier ();
}
/* Return true iff FN is a thread_local wrapper function. */
/* Avoid name clashes with aggregate initialization of multiple
references at once. */
write_unsigned_number (temp_count++);
- return finish_mangling_get_identifier (/*warn=*/false);
+ return finish_mangling_get_identifier ();
}
\f
gcc_unreachable ();
}
+/* Given a CLASS_TYPE, such as a record for std::bad_exception this
+ function generates a mangled name for the vtable map variable of
+ the class type. For example, if the class type is
+ "std::bad_exception", the mangled name for the class is
+ "St13bad_exception". This function would generate the name
+ "_ZN4_VTVISt13bad_exceptionE12__vtable_mapE", which unmangles as:
+ "_VTV<std::bad_exception>::__vtable_map". */
+
+
+char *
+get_mangled_vtable_map_var_name (tree class_type)
+{
+ char *var_name = NULL;
+ const char *prefix = "_ZN4_VTVI";
+ const char *postfix = "E12__vtable_mapE";
+
+ gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+ tree class_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+ unsigned int len = strlen (IDENTIFIER_POINTER (class_id)) +
+ strlen (prefix) +
+ strlen (postfix) + 1;
+
+ var_name = (char *) xmalloc (len);
+
+ sprintf (var_name, "%s%s%s", prefix, IDENTIFIER_POINTER (class_id), postfix);
+
+ return var_name;
+}
+
#include "gt-cp-mangle.h"