/* 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) { tree tcontext = targetm.cxx.decl_mangling_context (decl); if (tcontext != NULL_TREE) return tcontext; if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (TREE_TYPE (decl))) { tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)); if (extra) return extra; } else if (TREE_CODE (decl) == TYPE_DECL && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM) /* template type parms have no mangling context. */ return NULL_TREE; return CP_DECL_CONTEXT (decl); } /* ::= ::= ::= ::= 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 = decl_mangling_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 (TREE_CODE (node) == DECLTYPE_TYPE) { write_type (node); return; } 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); } /* ::=