From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/cp/mangle.c | 3489 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3489 insertions(+) create mode 100644 gcc/cp/mangle.c (limited to 'gcc/cp/mangle.c') diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c new file mode 100644 index 000000000..37412968f --- /dev/null +++ b/gcc/cp/mangle.c @@ -0,0 +1,3489 @@ +/* Name mangling for the 3.0 C++ ABI. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. + Written by Alex Samuel + + 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 +. */ + +/* 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 "tm.h" +#include "tree.h" +#include "tm_p.h" +#include "cp-tree.h" +#include "obstack.h" +#include "flags.h" +#include "target.h" +#include "cgraph.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), 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 from A, where A 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) \ + (TYPE_LANG_SPECIFIC (NODE) != NULL \ + && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM \ + || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL \ + && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))))) + +/* Things we only need one of. This module is not reentrant. */ +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; +} globals; + +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 + . 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 */ + 'n', /* itk_int128 */ + 'o', /* itk_unsigned_int128 */ +}; + +static int decl_is_template_id (const tree, tree* const); + +/* Functions for handling substitutions. */ + +static inline tree canonicalize_for_substitution (tree); +static void add_substitution (tree); +static inline int is_std_substitution (const tree, + const substitution_identifier_index_t); +static inline int is_std_substitution_char (const tree, + const substitution_identifier_index_t); +static int find_substitution (tree); +static void mangle_call_offset (const tree, const tree); + +/* 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_unscoped_name (const tree); +static void write_unscoped_template_name (const tree); +static void write_nested_name (const tree); +static void write_prefix (const tree); +static void write_template_prefix (const tree); +static void write_unqualified_name (const tree); +static void write_conversion_operator_name (const tree); +static void write_source_name (tree); +static 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 void write_special_name_constructor (const tree); +static void write_special_name_destructor (const tree); +static void write_type (tree); +static int write_CV_qualifiers_for_type (const tree); +static void write_builtin_type (tree); +static void write_function_type (const tree); +static void write_bare_function_type (const tree, const int, const tree); +static void write_method_parms (tree, const int, const tree); +static void write_class_enum_type (const tree); +static void write_template_args (tree); +static void write_expression (tree); +static void write_template_arg_literal (const tree); +static void write_template_arg (tree); +static void write_template_template_arg (const tree); +static void write_array_type (const tree); +static void write_pointer_to_member_type (const tree); +static void write_template_param (const tree); +static void write_template_template_param (const tree); +static void write_substitution (const int); +static int discriminator_for_local_entity (tree); +static int discriminator_for_string_literal (tree, tree); +static void write_discriminator (const int); +static void write_local_name (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. */ + +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. */ + +static void write_java_integer_type_codes (const tree); + +/* 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) + +/* If DECL is a template instance, return nonzero and, if + TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info. + Otherwise return zero. */ + +static int +decl_is_template_id (const tree decl, tree* const template_info) +{ + 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)) + { + if (template_info != NULL) + /* For a templated TYPE_DECL, the template info is hanging + off the type. */ + *template_info = TYPE_TEMPLATE_INFO (type); + return 1; + } + } + else + { + /* Check if this is a primary template. */ + if (DECL_LANG_SPECIFIC (decl) != NULL + && DECL_USE_TEMPLATE (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)) + && TREE_CODE (decl) != TEMPLATE_DECL) + { + if (template_info != NULL) + /* For most templated decls, the template info is hanging + off the decl. */ + *template_info = DECL_TEMPLATE_INFO (decl); + return 1; + } + } + + /* It's not a template id. */ + return 0; +} + +/* Produce debugging output of current substitution candidates. */ + +static void +dump_substitution_candidates (void) +{ + unsigned i; + tree el; + + fprintf (stderr, " ++ substitutions "); + FOR_EACH_VEC_ELT (tree, G.substitutions, i, el) + { + const char *name = "???"; + + if (i > 0) + fprintf (stderr, " "); + if (DECL_P (el)) + name = IDENTIFIER_POINTER (DECL_NAME (el)); + else if (TREE_CODE (el) == TREE_LIST) + name = IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (el))); + else if (TYPE_NAME (el)) + name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (el))); + fprintf (stderr, " S%d_ = ", i - 1); + if (TYPE_P (el) && + (CP_TYPE_RESTRICT_P (el) + || CP_TYPE_VOLATILE_P (el) + || CP_TYPE_CONST_P (el))) + fprintf (stderr, "CV-"); + fprintf (stderr, "%s (%s at %p)\n", + name, tree_code_name[TREE_CODE (el)], (void *) el); + } +} + +/* 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) + { + /* 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; +} + +/* 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", + 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); + node = c; + +#if ENABLE_CHECKING + /* Make sure NODE isn't already a candidate. */ + { + int i; + tree candidate; + + FOR_EACH_VEC_ELT (tree, G.substitutions, i, candidate) + { + gcc_assert (!(DECL_P (node) && node == candidate)); + gcc_assert (!(TYPE_P (node) && TYPE_P (candidate) + && same_type_p (node, candidate))); + } + } +#endif /* ENABLE_CHECKING */ + + /* Put the decl onto the varray of substitution candidates. */ + VEC_safe_push (tree, gc, G.substitutions, node); + + if (DEBUG_MANGLE) + dump_substitution_candidates (); +} + +/* Helper function for find_substitution. Returns nonzero if NODE, + which may be a decl or a CLASS_TYPE, is a template-id with template + name of substitution_index[INDEX] in the ::std namespace. */ + +static inline int +is_std_substitution (const tree node, + const substitution_identifier_index_t index) +{ + tree type = NULL; + tree decl = NULL; + + if (DECL_P (node)) + { + type = TREE_TYPE (node); + decl = node; + } + else if (CLASS_TYPE_P (node)) + { + type = node; + decl = TYPE_NAME (node); + } + else + /* These are not the droids you're looking for. */ + return 0; + + return (DECL_NAMESPACE_STD_P (CP_DECL_CONTEXT (decl)) + && TYPE_LANG_SPECIFIC (type) + && TYPE_TEMPLATE_INFO (type) + && (DECL_NAME (TYPE_TI_TEMPLATE (type)) + == subst_identifiers[index])); +} + +/* Helper function for find_substitution. Returns nonzero if NODE, + which may be a decl or a CLASS_TYPE, is the template-id + ::std::identifier, where identifier is + substitution_index[INDEX]. */ + +static inline int +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 . */ + 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. + + ::= St + # ::std + + ::= Sa + # ::std::allocator + + ::= Sb + # ::std::basic_string + + ::= Ss + # ::std::basic_string, + ::std::allocator > + + ::= Si + # ::std::basic_istream > + + ::= So + # ::std::basic_ostream > + + ::= Sd + # ::std::basic_iostream > + + Then examine the stack of currently available substitution + candidates for entities appearing earlier in the same mangling + + If a substitution is found, write its mangled representation and + return nonzero. If none is found, just return zero. */ + +static int +find_substitution (tree node) +{ + int i; + const int size = VEC_length (tree, G.substitutions); + tree decl; + tree type; + + if (DEBUG_MANGLE) + fprintf (stderr, " ++ find_substitution (%s at %p)\n", + tree_code_name[TREE_CODE (node)], (void *) node); + + /* Obtain the canonicalized substitution representation for NODE. + This is what we'll compare against. */ + node = canonicalize_for_substitution (node); + + /* Check for builtin substitutions. */ + + decl = TYPE_P (node) ? TYPE_NAME (node) : node; + type = TYPE_P (node) ? node : TREE_TYPE (node); + + /* Check for std::allocator. */ + if (decl + && is_std_substitution (decl, SUBID_ALLOCATOR) + && !CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl))) + { + write_string ("Sa"); + return 1; + } + + /* Check for std::basic_string. */ + if (decl && is_std_substitution (decl, SUBID_BASIC_STRING)) + { + if (TYPE_P (node)) + { + /* If this is a type (i.e. a fully-qualified template-id), + check for + std::basic_string , + std::allocator > . */ + if (cp_type_quals (type) == TYPE_UNQUALIFIED + && CLASSTYPE_USE_TEMPLATE (type)) + { + tree args = CLASSTYPE_TI_ARGS (type); + if (TREE_VEC_LENGTH (args) == 3 + && same_type_p (TREE_VEC_ELT (args, 0), char_type_node) + && is_std_substitution_char (TREE_VEC_ELT (args, 1), + SUBID_CHAR_TRAITS) + && is_std_substitution_char (TREE_VEC_ELT (args, 2), + SUBID_ALLOCATOR)) + { + write_string ("Ss"); + return 1; + } + } + } + else + /* Substitute for the template name only if this isn't a type. */ + { + write_string ("Sb"); + return 1; + } + } + + /* 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) + { + /* First, check for the template + args > . */ + tree args = CLASSTYPE_TI_ARGS (type); + if (TREE_VEC_LENGTH (args) == 2 + && TYPE_P (TREE_VEC_ELT (args, 0)) + && same_type_p (TREE_VEC_ELT (args, 0), char_type_node) + && is_std_substitution_char (TREE_VEC_ELT (args, 1), + SUBID_CHAR_TRAITS)) + { + /* Got them. Is this basic_istream? */ + if (is_std_substitution (decl, SUBID_BASIC_ISTREAM)) + { + write_string ("Si"); + return 1; + } + /* Or basic_ostream? */ + else if (is_std_substitution (decl, SUBID_BASIC_OSTREAM)) + { + write_string ("So"); + return 1; + } + /* Or basic_iostream? */ + else if (is_std_substitution (decl, SUBID_BASIC_IOSTREAM)) + { + write_string ("Sd"); + return 1; + } + } + } + + /* Check for namespace std. */ + if (decl && DECL_NAMESPACE_STD_P (decl)) + { + write_string ("St"); + return 1; + } + + /* Now check the list of available substitutions for this mangling + operation. */ + for (i = 0; i < size; ++i) + { + tree candidate = VEC_index (tree, G.substitutions, i); + /* 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) + && same_type_p (type, candidate)) + || NESTED_TEMPLATE_MATCH (node, candidate)) + { + write_substitution (i); + return 1; + } + } + + /* No substitution found. */ + return 0; +} + + +/* TOP_LEVEL is true, if this is being called at outermost level of + mangling. It should be false when mangling a decl appearing in an + expression within some other mangling. + + ::= _Z */ + +static void +write_mangled_name (const tree decl, bool top_level) +{ + MANGLE_TRACE_TREE ("mangled-name", decl); + + if (/* The names of `extern "C"' functions are not mangled. */ + DECL_EXTERN_C_FUNCTION_P (decl) + /* But overloaded operator names *are* mangled. */ + && !DECL_OVERLOADED_OPERATOR_P (decl)) + { + unmangled_name:; + + if (top_level) + write_string (IDENTIFIER_POINTER (DECL_NAME (decl))); + else + { + /* The standard notes: "The of an extern "C" + function is treated like global-scope data, i.e. as its + 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_source_name (DECL_NAME (decl)); + } + } + else if (TREE_CODE (decl) == VAR_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; + } + } + 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* "); + } +} + +/* ::= + ::= */ + +static void +write_encoding (const tree decl) +{ + MANGLE_TRACE_TREE ("encoding", decl); + + if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl)) + { + /* For overloaded operators write just the mangled name + without arguments. */ + if (DECL_OVERLOADED_OPERATOR_P (decl)) + write_name (decl, /*ignore_local_scope=*/0); + else + write_source_name (DECL_NAME (decl)); + return; + } + + write_name (decl, /*ignore_local_scope=*/0); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + tree fn_type; + tree d; + + if (decl_is_template_id (decl, NULL)) + { + fn_type = get_mostly_instantiated_function_type (decl); + /* FN_TYPE will not have parameter types for in-charge or + VTT parameters. Therefore, we pass NULL_TREE to + write_bare_function_type -- otherwise, it will get + confused about which artificial parameters to skip. */ + d = NULL_TREE; + } + else + { + fn_type = TREE_TYPE (decl); + d = decl; + } + + write_bare_function_type (fn_type, + (!DECL_CONSTRUCTOR_P (decl) + && !DECL_DESTRUCTOR_P (decl) + && !DECL_CONV_FN_P (decl) + && decl_is_template_id (decl, NULL)), + d); + } +} + +/* 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); +} + +/* ::= + ::= + ::= + ::= + + If IGNORE_LOCAL_SCOPE is nonzero, this production of is + called from , which mangles the enclosing scope + elsewhere and then uses this function to mangle just the part + underneath the function scope. So don't use the + production, to avoid an infinite recursion. */ + +static void +write_name (tree decl, const int ignore_local_scope) +{ + tree context; + + MANGLE_TRACE_TREE ("name", decl); + + if (TREE_CODE (decl) == TYPE_DECL) + { + /* 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 = decl_mangling_context (decl); + + /* A decl in :: or ::std scope is treated specially. The former is + mangled using or , the + latter with a special substitution. Also, a name that is + directly in a local function scope is also mangled with + rather than a full . */ + if (context == NULL + || context == global_namespace + || DECL_NAMESPACE_STD_P (context) + || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL)) + { + tree template_info; + /* Is this a template instance? */ + if (decl_is_template_id (decl, &template_info)) + { + /* Yes: use . */ + write_unscoped_template_name (TI_TEMPLATE (template_info)); + write_template_args (TI_ARGS (template_info)); + } + else + /* Everything else gets an . */ + write_unscoped_name (decl); + } + else + { + /* Handle local names, unless we asked not to (that is, invoked + under , to handle only the part of the name under + the local scope). */ + if (!ignore_local_scope) + { + /* Scan up the list of scope context, looking for a + function. If we find one, this entity is in local + function scope. local_entity tracks context one scope + level down, so it will contain the element that's + directly in that function's scope, either decl or one of + its enclosing scopes. */ + tree local_entity = decl; + while (context != NULL && context != global_namespace) + { + /* Make sure we're always dealing with decls. */ + if (context != NULL && TYPE_P (context)) + context = TYPE_NAME (context); + /* Is this a function? */ + if (TREE_CODE (context) == FUNCTION_DECL + || TREE_CODE (context) == PARM_DECL) + { + /* Yes, we have local scope. Use the + production for the innermost function scope. */ + write_local_name (context, local_entity, decl); + return; + } + /* Up one scope level. */ + local_entity = context; + context = decl_mangling_context (context); + } + + /* No local scope found? Fall through to . */ + } + + /* Other decls get a to encode their scope. */ + write_nested_name (decl); + } +} + +/* ::= + ::= St # ::std:: */ + +static void +write_unscoped_name (const tree decl) +{ + tree context = CP_DECL_CONTEXT (decl); + + MANGLE_TRACE_TREE ("unscoped-name", decl); + + /* Is DECL in ::std? */ + if (DECL_NAMESPACE_STD_P (context)) + { + write_string ("St"); + write_unqualified_name (decl); + } + else + { + /* If not, it should be either in the global namespace, or directly + in a local function scope. */ + gcc_assert (context == global_namespace + || context != NULL + || TREE_CODE (context) == FUNCTION_DECL); + + write_unqualified_name (decl); + } +} + +/* ::= + ::= */ + +static void +write_unscoped_template_name (const tree decl) +{ + MANGLE_TRACE_TREE ("unscoped-template-name", decl); + + if (find_substitution (decl)) + return; + write_unscoped_name (decl); + add_substitution (decl); +} + +/* Write the nested name, including CV-qualifiers, of DECL. + + ::= N [] E + ::= N [] E + + ::= [r] [V] [K] */ + +static void +write_nested_name (const tree decl) +{ + tree template_info; + + MANGLE_TRACE_TREE ("nested-name", decl); + + write_char ('N'); + + /* Write CV-qualifiers, if this is a member function. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + { + if (DECL_VOLATILE_MEMFUNC_P (decl)) + write_char ('V'); + if (DECL_CONST_MEMFUNC_P (decl)) + write_char ('K'); + } + + /* Is this a template instance? */ + if (decl_is_template_id (decl, &template_info)) + { + /* Yes, use . */ + 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 */ + write_prefix (CP_DECL_CONTEXT (decl)); + write_unqualified_name (decl); + } + write_char ('E'); +} + +/* ::= + ::= + ::= + ::= # empty + ::= */ + +static void +write_prefix (const tree node) +{ + tree decl; + /* Non-NULL if NODE represents a template-id. */ + tree template_info = NULL; + + if (node == NULL + || node == global_namespace) + return; + + MANGLE_TRACE_TREE ("prefix", node); + + if (find_substitution (node)) + return; + + if (DECL_P (node)) + { + /* 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 production, which encodes + the enclosing function scope elsewhere. So don't continue + here. */ + if (TREE_CODE (node) == FUNCTION_DECL + || TREE_CODE (node) == PARM_DECL) + return; + + decl = node; + decl_is_template_id (decl, &template_info); + } + else + { + /* Node is a type. */ + decl = TYPE_NAME (node); + if (CLASSTYPE_TEMPLATE_ID_P (node)) + 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)) + write_template_param (node); + else if (template_info != NULL) + /* Templated. */ + { + 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 (decl_mangling_context (decl)); + write_unqualified_name (decl); + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FIELD_DECL) + { + /* := M */ + write_char ('M'); + return; + } + } + + add_substitution (node); +} + +/* ::=