/* Name mangling for the 3.0 -*- C++ -*- ABI.
Copyright (C) 2000-2026 Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* This file implements mangling of C++ names according to the IA64
C++ ABI specification. A mangled name encodes a function or
variable's name, scope, type, and/or template arguments into a text
identifier. This identifier is used as the function's or
variable's linkage name, to preserve compatibility between C++'s
language features (templates, scoping, and overloading) and C
linkers.
Additionally, g++ uses mangled names internally. To support this,
mangling of types is allowed, even though the mangled name of a
type should not appear by itself as an exported name. Ditto for
uninstantiated templates.
The primary entry point for this module is mangle_decl, which
returns an identifier containing the mangled name for a decl.
Additional entry points are provided to build mangled names of
particular constructs when the appropriate decl for that construct
is not available. These are:
mangle_typeinfo_for_type: typeinfo data
mangle_typeinfo_string_for_type: typeinfo type name
mangle_vtbl_for_type: virtual table data
mangle_vtt_for_type: VTT data
mangle_ctor_vtbl_for_type: `C-in-B' constructor virtual table data
mangle_thunk: thunk function or entry */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "vtable-verify.h"
#include "cp-tree.h"
#include "stringpool.h"
#include "cgraph.h"
#include "stor-layout.h"
#include "flags.h"
#include "attribs.h"
#include "contracts.h"
/* Debugging support. */
/* Define DEBUG_MANGLE to enable very verbose trace messages. */
#ifndef DEBUG_MANGLE
#define DEBUG_MANGLE 0
#endif
/* Macros for tracing the write_* functions. */
#if DEBUG_MANGLE
# define MANGLE_TRACE(FN, INPUT) \
fprintf (stderr, " %-24s: %-24s\n", (FN), (INPUT))
# define MANGLE_TRACE_TREE(FN, NODE) \
fprintf (stderr, " %-24s: %-24s (%p)\n", \
(FN), get_tree_code_name (TREE_CODE (NODE)), (void *) (NODE))
#else
# define MANGLE_TRACE(FN, INPUT)
# define MANGLE_TRACE_TREE(FN, NODE)
#endif
/* Nonzero if NODE is a class template-id. We can't rely on
CLASSTYPE_USE_TEMPLATE here because of tricky bugs in the parser
that hard to distinguish A<T> from A, where A<T> is the type as
instantiated outside of the template, and A is the type used
without parameters inside the template. */
#define CLASSTYPE_TEMPLATE_ID_P(NODE) \
(TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM \
|| (CLASS_TYPE_P (NODE) \
&& CLASSTYPE_TEMPLATE_INFO (NODE) != NULL \
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))
/* For deciding whether to set G.need_abi_warning, we need to consider both
warn_abi_version and flag_abi_compat_version. */
#define abi_warn_or_compat_version_crosses(N) \
(abi_version_crosses (N) || abi_compat_version_crosses (N))
/* And sometimes we can simplify the code path if we don't need to worry about
previous ABIs. */
#define abi_flag_at_least(flag,N) (flag == 0 || flag >= N)
#define any_abi_below(N) \
(!abi_version_at_least (N) \
|| !abi_flag_at_least (warn_abi_version, (N)) \
|| !abi_flag_at_least (flag_abi_compat_version, (N)))
/* Things we only need one of. This module is not reentrant. */
struct GTY(()) globals {
/* An array of the current substitution candidates, in the order
we've seen them. Contains NULLS, which correspond to module
substitutions. */
vec<tree, va_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;
/* True if the mangling will be different in C++17 mode. */
bool need_cxx17_warning;
/* True if we mangled a module name. */
bool mod;
};
static GTY (()) globals G;
/* The obstack on which we build mangled names. */
static struct obstack *mangle_obstack;
/* The obstack on which we build mangled names that are not going to
be IDENTIFIER_NODEs. */
static struct obstack name_obstack;
/* The first object on the name_obstack; we use this to free memory
allocated on the name_obstack. */
static void *name_base;
/* Indices into subst_identifiers. These are identifiers used in
special substitution rules. */
typedef enum
{
SUBID_ALLOCATOR,
SUBID_BASIC_STRING,
SUBID_CHAR_TRAITS,
SUBID_BASIC_ISTREAM,
SUBID_BASIC_OSTREAM,
SUBID_BASIC_IOSTREAM,
SUBID_MAX
}
substitution_identifier_index_t;
/* For quick substitution checks, look up these common identifiers
once only. */
static GTY(()) tree subst_identifiers[SUBID_MAX];
/* Single-letter codes for builtin integer types, defined in
<builtin-type>. These are indexed by integer_type_kind values. */
static const char
integer_type_codes[itk_none] =
{
'c', /* itk_char */
'a', /* itk_signed_char */
'h', /* itk_unsigned_char */
's', /* itk_short */
't', /* itk_unsigned_short */
'i', /* itk_int */
'j', /* itk_unsigned_int */
'l', /* itk_long */
'm', /* itk_unsigned_long */
'x', /* itk_long_long */
'y', /* itk_unsigned_long_long */
/* __intN types are handled separately */
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
};
static tree maybe_template_info (const tree);
/* Functions for handling substitutions. */
static inline tree canonicalize_for_substitution (tree);
static void add_substitution (tree);
static inline bool is_std_substitution (const tree,
const substitution_identifier_index_t);
static inline bool is_std_substitution_char (const tree,
const substitution_identifier_index_t);
static int find_substitution (tree);
static void mangle_call_offset (const tree, const tree);
/* Functions for emitting mangled representations of things. */
static void write_mangled_name (const tree, bool);
static void write_encoding (const tree);
static void write_name (tree, const int);
static void write_abi_tags (tree);
static void write_unscoped_name (const tree);
static void write_unscoped_template_name (const tree);
static void write_nested_name (const tree);
static void write_prefix (const tree);
static void write_template_prefix (const tree);
static void write_unqualified_name (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_unnamed_enum_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 void write_special_name_constructor (const tree);
static void write_special_name_destructor (const tree);
static void write_type (tree);
static int write_CV_qualifiers_for_type (const tree);
static void write_builtin_type (tree);
static void write_function_type (const tree);
static void write_bare_function_type (const tree, const int, const tree);
static void write_method_parms (tree, const int, const tree);
static void write_class_enum_type (const tree);
static void write_template_args (tree, tree = NULL_TREE);
static void write_expression (tree);
static void write_template_arg_literal (const tree);
static void write_template_arg (tree);
static void write_template_template_arg (const tree);
static void write_array_type (const tree);
static void write_pointer_to_member_type (const tree);
static void write_template_param (const tree);
static void write_template_template_param (const tree);
static void write_substitution (const int);
static int discriminator_for_local_entity (tree);
static int discriminator_for_string_literal (tree, tree);
static void write_discriminator (const int);
static void write_local_name (tree, const tree, const tree);
static void dump_substitution_candidates (void);
static tree mangle_decl_string (const tree);
static void maybe_check_abi_tags (tree, tree = NULL_TREE, int = 10);
/* Control functions. */
static inline void start_mangling (const tree);
static tree mangle_special_for_type (const tree, const char *);
/* Append a single character to the end of the mangled
representation. */
#define write_char(CHAR) \
obstack_1grow (mangle_obstack, (CHAR))
/* Append a sized buffer to the end of the mangled representation. */
#define write_chars(CHAR, LEN) \
obstack_grow (mangle_obstack, (CHAR), (LEN))
/* Append a NUL-terminated string to the end of the mangled
representation. */
#define write_string(STRING) \
obstack_grow (mangle_obstack, (STRING), strlen (STRING))
/* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
same purpose (context, which may be a type) and value (template
decl). See write_template_prefix for more information on what this
is used for. */
#define NESTED_TEMPLATE_MATCH(NODE1, NODE2) \
(TREE_CODE (NODE1) == TREE_LIST \
&& TREE_CODE (NODE2) == TREE_LIST \
&& ((TYPE_P (TREE_PURPOSE (NODE1)) \
&& same_type_p (TREE_PURPOSE (NODE1), TREE_PURPOSE (NODE2))) \
|| TREE_PURPOSE (NODE1) == TREE_PURPOSE (NODE2)) \
&& TREE_VALUE (NODE1) == TREE_VALUE (NODE2))
/* Write out an unsigned quantity in base 10. */
#define write_unsigned_number(NUMBER) \
write_number ((NUMBER), /*unsigned_p=*/1, 10)
/* Check for -fabi-version dependent mangling and also set the need_abi_warning
flag as appropriate. */
static bool
abi_check (int ver)
{
if (abi_warn_or_compat_version_crosses (ver))
G.need_abi_warning = true;
return abi_version_at_least (ver);
}
/* If DECL is a template instance (including the uninstantiated template
itself), return its TEMPLATE_INFO. Otherwise return NULL. */
static tree
maybe_template_info (const tree decl)
{
if (TREE_CODE (decl) == TYPE_DECL)
{
/* TYPE_DECLs are handled specially. Look at its type to decide
if this is a template instantiation. */
const tree type = TREE_TYPE (decl);
if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_ID_P (type))
return TYPE_TEMPLATE_INFO (type);
}
else
{
/* Check if the template is a primary template. */
if (DECL_LANG_SPECIFIC (decl) != NULL
&& VAR_OR_FUNCTION_DECL_P (decl)
&& DECL_TEMPLATE_INFO (decl)
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
return DECL_TEMPLATE_INFO (decl);
}
/* It's not a template id. */
return NULL_TREE;
}
/* Produce debugging output of current substitution candidates. */
static void
dump_substitution_candidates (void)
{
unsigned i;
tree el;
fprintf (stderr, " ++ substitutions ");
FOR_EACH_VEC_ELT (*G.substitutions, i, el)
{
const char *name = "???";
if (i > 0)
fprintf (stderr, " ");
if (!el)
name = "module";
else if (DECL_P (el))
name = IDENTIFIER_POINTER (DECL_NAME (el));
else if (TREE_CODE (el) == TREE_LIST)
name = IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (el)));
else if (TYPE_NAME (el))
name = TYPE_NAME_STRING (el);
fprintf (stderr, " S%d_ = ", i - 1);
if (el)
{
if (TYPE_P (el) &&
(CP_TYPE_RESTRICT_P (el)
|| CP_TYPE_VOLATILE_P (el)
|| CP_TYPE_CONST_P (el)))
fprintf (stderr, "CV-");
fprintf (stderr, "%s (%s at %p)",
name, get_tree_code_name (TREE_CODE (el)), (void *) el);
}
fprintf (stderr, "\n");
}
}
/* <exception-spec> ::=
Do -- non-throwing exception specification
DO <expression> E -- computed (instantiation-dependent) noexcept
Dw <type>* E -- throw (types) */
static void
write_exception_spec (tree spec)
{
if (!spec || spec == noexcept_false_spec)
/* Nothing. */
return;
if (!flag_noexcept_type)
{
G.need_cxx17_warning = true;
return;
}
if (spec == noexcept_true_spec || spec == empty_except_spec)
write_string ("Do");
else if (tree expr = TREE_PURPOSE (spec))
{
/* noexcept (expr) */
gcc_assert (uses_template_parms (expr));
write_string ("DO");
write_expression (expr);
write_char ('E');
}
else
{
/* throw (type-list) */
write_string ("Dw");
for (tree t = spec; t; t = TREE_CHAIN (t))
write_type (TREE_VALUE (t));
write_char ('E');
}
}
/* Both decls and types can be substitution candidates, but sometimes
they refer to the same thing. For instance, a TYPE_DECL and
RECORD_TYPE for the same class refer to the same thing, and should
be treated accordingly in substitutions. This function returns a
canonicalized tree node representing NODE that is used when adding
and substitution candidates and finding matches. */
static inline tree
canonicalize_for_substitution (tree node)
{
/* For a TYPE_DECL, use the type instead. */
if (TREE_CODE (node) == TYPE_DECL)
node = TREE_TYPE (node);
if (TYPE_P (node)
&& 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. */
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));
if (FUNC_OR_METHOD_TYPE_P (node))
{
node = build_ref_qualified_type (node, type_memfn_rqual (orig));
tree r = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (orig));
if (flag_noexcept_type)
node = build_exception_variant (node, r);
else
/* Set the warning flag if appropriate. */
write_exception_spec (r);
}
}
return node;
}
/* Add NODE as a substitution candidate. NODE must not already be on
the list of candidates. */
static void
add_substitution (tree node)
{
tree c;
if (DEBUG_MANGLE)
fprintf (stderr, " ++ add_substitution (%s at %10p)\n",
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",
get_tree_code_name (TREE_CODE (node)), (void *) node);
node = c;
/* Make sure NODE isn't already a candidate. */
if (flag_checking)
{
int i;
tree candidate;
FOR_EACH_VEC_SAFE_ELT (G.substitutions, i, candidate)
if (candidate)
{
gcc_assert (!(DECL_P (node) && node == candidate));
gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
&& same_type_p (node, candidate)));
}
}
/* Put the decl onto the varray of substitution candidates. */
vec_safe_push (G.substitutions, node);
if (DEBUG_MANGLE)
dump_substitution_candidates ();
}
/* Helper function for find_substitution. Returns nonzero if NODE,
which may be a class or a class template, is a template-id with template
name of substitution_index[INDEX] in the ::std namespace, with
global module attachment. */
static bool
is_std_substitution (const tree node,
const substitution_identifier_index_t index)
{
tree type = NULL_TREE;
tree decl = NULL_TREE;
auto std_substitution_p = [&] (tree decl, tree type)
{
if (!DECL_NAMESPACE_STD_P (CP_DECL_CONTEXT (decl)))
return false;
if (!(TYPE_LANG_SPECIFIC (type) && TYPE_TEMPLATE_INFO (type)))
return false;
tree tmpl = TYPE_TI_TEMPLATE (type);
if (DECL_NAME (tmpl) != subst_identifiers[index])
return false;
if (modules_p () && get_originating_module (tmpl, true) >= 0)
return false;
return true;
};
if (TREE_CODE (node) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (node))
{
type = TREE_TYPE (node);
decl = node;
}
else if (CLASS_TYPE_P (node))
{
type = node;
decl = TYPE_NAME (node);
}
else
{
/* We used to accept all _DECL nodes in this function but now we
only accept classes or class templates. Verify that we don't
return false for something that used to yield true. */
gcc_checking_assert (!DECL_P (node)
|| !std_substitution_p (node, TREE_TYPE (node)));
/* These are not the droids you're looking for. */
return false;
}
return std_substitution_p (decl, type);
}
/* Return the ABI tags (the TREE_VALUE of the "abi_tag" attribute entry) for T,
which can be a decl or type. */
static tree
get_abi_tags (tree t)
{
if (!t || TREE_CODE (t) == NAMESPACE_DECL)
return NULL_TREE;
if (DECL_P (t) && DECL_DECLARES_TYPE_P (t))
t = TREE_TYPE (t);
if (TREE_CODE (t) == TEMPLATE_DECL && DECL_TEMPLATE_RESULT (t))
{
tree tags = get_abi_tags (DECL_TEMPLATE_RESULT (t));
/* We used to overlook abi_tag on function and variable templates. */
if (tags && abi_check (19))
return tags;
else
return NULL_TREE;
}
tree attrs;
if (TYPE_P (t))
attrs = TYPE_ATTRIBUTES (t);
else
attrs = DECL_ATTRIBUTES (t);
tree tags = lookup_attribute ("abi_tag", attrs);
if (tags)
tags = TREE_VALUE (tags);
return tags;
}
/* Helper function for find_substitution. Returns nonzero if NODE,
which may be a decl or a CLASS_TYPE, is the template-id
::std::identifier<char>, where identifier is
substitution_index[INDEX]. */
static bool
is_std_substitution_char (const tree node,
const substitution_identifier_index_t index)
{
tree args;
/* Check NODE's name is ::std::identifier. */
if (!is_std_substitution (node, index))
return 0;
/* Figure out its template args. */
if (DECL_P (node))
args = DECL_TI_ARGS (node);
else if (CLASS_TYPE_P (node))
args = CLASSTYPE_TI_ARGS (node);
else
/* Oops, not a template. */
return 0;
/* NODE's template arg list should be <char>. */
return
TREE_VEC_LENGTH (args) == 1
&& TREE_VEC_ELT (args, 0) == char_type_node;
}
/* Check whether a substitution should be used to represent NODE in
the mangling.
First, check standard special-case substitutions.
<substitution> ::= St
# ::std
::= Sa
# ::std::allocator
::= Sb
# ::std::basic_string
::= Ss
# ::std::basic_string<char,
|