X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gcc%2Fcp%2Fmangle.c;h=6b8f7066aa01e63dea20a8d65512e07b1f9fee9d;hb=2a22f99cb12d82712dd93cfef808b1cef543601b;hp=f4efa67cc2732f7c9a0a42ae7c3b84ddc634a2de;hpb=4b6aaa996e0d8f5abac818315b6f77cb3596db98;p=platform%2Fupstream%2Fgcc.git diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index f4efa67..6b8f706 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1,6 +1,5 @@ /* 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. + Copyright (C) 2000-2014 Free Software Foundation, Inc. Written by Alex Samuel This file is part of GCC. @@ -50,12 +49,16 @@ along with GCC; see the file COPYING3. If not see #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. */ @@ -70,7 +73,7 @@ along with GCC; see the file COPYING3. If not see 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) @@ -91,7 +94,7 @@ along with GCC; see the file COPYING3. If not see typedef struct GTY(()) globals { /* An array of the current substitution candidates, in the order we've seen them. */ - VEC(tree,gc) *substitutions; + vec *substitutions; /* The entity that is being mangled. */ tree GTY ((skip)) entity; @@ -173,12 +176,13 @@ static void mangle_call_offset (const tree, const tree); 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 (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); @@ -222,7 +226,6 @@ 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. */ @@ -310,7 +313,7 @@ dump_substitution_candidates (void) tree el; fprintf (stderr, " ++ substitutions "); - FOR_EACH_VEC_ELT (tree, G.substitutions, i, el) + FOR_EACH_VEC_ELT (*G.substitutions, i, el) { const char *name = "???"; @@ -321,7 +324,7 @@ dump_substitution_candidates (void) 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) @@ -329,7 +332,7 @@ dump_substitution_candidates (void) || 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); } } @@ -350,6 +353,7 @@ canonicalize_for_substitution (tree 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. */ @@ -361,6 +365,9 @@ canonicalize_for_substitution (tree node) 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; } @@ -375,13 +382,13 @@ add_substitution (tree 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 @@ -390,7 +397,7 @@ add_substitution (tree node) int i; tree candidate; - FOR_EACH_VEC_ELT (tree, G.substitutions, i, candidate) + FOR_EACH_VEC_SAFE_ELT (G.substitutions, i, candidate) { gcc_assert (!(DECL_P (node) && node == candidate)); gcc_assert (!(TYPE_P (node) && TYPE_P (candidate) @@ -400,7 +407,7 @@ add_substitution (tree node) #endif /* ENABLE_CHECKING */ /* Put the decl onto the varray of substitution candidates. */ - VEC_safe_push (tree, gc, G.substitutions, node); + vec_safe_push (G.substitutions, node); if (DEBUG_MANGLE) dump_substitution_candidates (); @@ -503,13 +510,14 @@ static int find_substitution (tree node) { int i; - const int size = VEC_length (tree, G.substitutions); + 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. */ @@ -524,13 +532,10 @@ find_substitution (tree node) 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)) { @@ -549,26 +554,20 @@ find_substitution (tree 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 > . */ @@ -581,41 +580,35 @@ find_substitution (tree node) { /* 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 = VEC_index (tree, G.substitutions, i); + tree candidate = (*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) + || (TYPE_P (candidate) && type && TYPE_P (node) && same_type_p (type, candidate)) || NESTED_TEMPLATE_MATCH (node, candidate)) { @@ -624,8 +617,19 @@ find_substitution (tree node) } } - /* 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; } @@ -656,40 +660,25 @@ write_mangled_name (const tree decl, bool top_level) 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* "); } } @@ -753,6 +742,10 @@ decl_mangling_context (tree decl) 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))) { @@ -794,15 +787,24 @@ write_name (tree decl, const int ignore_local_scope) 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 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 + if (context == global_namespace || DECL_NAMESPACE_STD_P (context) - || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL)) + || (ignore_local_scope + && (TREE_CODE (context) == FUNCTION_DECL + || (abi_version_at_least (7) + && TREE_CODE (context) == PARM_DECL)))) { tree template_info; /* Is this a template instance? */ @@ -830,10 +832,10 @@ write_name (tree decl, const int ignore_local_scope) 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 @@ -876,9 +878,10 @@ write_unscoped_name (const tree 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); @@ -901,9 +904,11 @@ write_unscoped_template_name (const tree decl) /* Write the nested name, including CV-qualifiers, of DECL. - ::= N [] E - ::= N [] E + ::= N [] [] E + ::= N [] [] E + ::= R # & ref-qualifier + ::= O # && ref-qualifier ::= [r] [V] [K] */ static void @@ -923,6 +928,13 @@ write_nested_name (const tree decl) 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? */ @@ -942,14 +954,14 @@ write_nested_name (const tree decl) } else { - write_prefix (CP_DECL_CONTEXT (decl)); + write_prefix (decl_mangling_context (decl)); write_unqualified_name (decl); } } else { /* No, just use */ - write_prefix (CP_DECL_CONTEXT (decl)); + write_prefix (decl_mangling_context (decl)); write_unqualified_name (decl); } write_char ('E'); @@ -1006,13 +1018,7 @@ write_prefix (const tree 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)) + if (TREE_CODE (node) == TEMPLATE_TYPE_PARM) write_template_param (node); else if (template_info != NULL) /* Templated. */ @@ -1030,7 +1036,7 @@ write_prefix (const tree node) } else { - write_prefix (CP_DECL_CONTEXT (decl)); + write_prefix (decl_mangling_context (decl)); write_unqualified_name (decl); } } @@ -1039,7 +1045,7 @@ write_prefix (const tree node) { 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) { /* := M */ @@ -1060,7 +1066,7 @@ write_template_prefix (const tree node) { tree decl = DECL_P (node) ? node : TYPE_NAME (node); tree type = DECL_P (node) ? TREE_TYPE (node) : node; - tree context = CP_DECL_CONTEXT (decl); + tree context = decl_mangling_context (decl); tree template_info; tree templ; tree substitution; @@ -1110,15 +1116,8 @@ write_template_prefix (const tree node) 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 { @@ -1182,25 +1181,27 @@ write_unqualified_id (tree identifier) } 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; } + bool found = false; + if (DECL_NAME (decl) == NULL_TREE) { + found = true; gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); write_source_name (DECL_ASSEMBLER_NAME (decl)); - return; } else if (DECL_DECLARES_FUNCTION_P (decl)) { - bool found = true; + found = true; if (DECL_CONSTRUCTOR_P (decl)) write_special_name_constructor (decl); else if (DECL_DESTRUCTOR_P (decl)) @@ -1216,6 +1217,9 @@ write_unqualified_name (const tree decl) 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); @@ -1234,14 +1238,13 @@ write_unqualified_name (const tree decl) write_literal_operator_name (DECL_NAME (decl)); else found = false; - - if (found) - return; } - if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl) - && DECL_NAMESPACE_SCOPE_P (decl) - && decl_linkage (decl) == lk_internal) + if (found) + /* OK */; + else if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl) + && DECL_NAMESPACE_SCOPE_P (decl) + && decl_linkage (decl) == lk_internal) { MANGLE_TRACE_TREE ("local-source-name", decl); write_char ('L'); @@ -1262,6 +1265,22 @@ write_unqualified_name (const tree decl) else write_source_name (DECL_NAME (decl)); } + + /* 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. */ @@ -1291,19 +1310,64 @@ write_source_name (tree identifier) write_identifier (IDENTIFIER_POINTER (identifier)); } +/* Compare two TREE_STRINGs like strcmp. */ + +int +tree_string_cmp (const void *p1, const void *p2) +{ + if (p1 == p2) + return 0; + tree s1 = *(const tree*)p1; + tree s2 = *(const tree*)p2; + return strcmp (TREE_STRING_POINTER (s1), + TREE_STRING_POINTER (s2)); +} + +/* ID is the name of a function or type with abi_tags attribute TAGS. + Write out the name, suitably decorated. */ + +static void +write_abi_tags (tree tags) +{ + if (tags == NULL_TREE) + return; + + tags = TREE_VALUE (tags); + + vec * vec = make_tree_vector(); + + 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); + } + + vec->qsort (tree_string_cmp); + + unsigned i; tree str; + FOR_EACH_VEC_ELT (*vec, i, str) + { + write_string ("B"); + write_unsigned_number (TREE_STRING_LENGTH (str) - 1); + write_identifier (TREE_STRING_POINTER (str)); + } + + release_tree_vector (vec); +} + /* Write a user-defined literal operator. + ::= li # "" IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */ static void write_literal_operator_name (tree identifier) { const char* suffix = UDLIT_OP_SUFFIX (identifier); - char* buffer = XNEWVEC (char, strlen (UDLIT_OP_MANGLED_PREFIX) - + strlen (suffix) + 10); - sprintf (buffer, UDLIT_OP_MANGLED_FORMAT, suffix); - - write_unsigned_number (strlen (buffer)); - write_identifier (buffer); + write_identifier (UDLIT_OP_MANGLED_PREFIX); + write_unsigned_number (strlen (suffix)); + write_identifier (suffix); } /* Encode 0 as _, and 1+ as n-1_. */ @@ -1339,7 +1403,7 @@ nested_anon_class_index (tree type) /* ::= Ut [ ] _ */ static void -write_unnamed_type_name (const tree type ATTRIBUTE_UNUSED) +write_unnamed_type_name (const tree type) { int discriminator; MANGLE_TRACE_TREE ("unnamed-type-name", type); @@ -1381,7 +1445,7 @@ write_closure_type_name (const tree type) /* 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 @@ -1435,8 +1499,8 @@ static inline void 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. */ @@ -1462,8 +1526,7 @@ write_integer_cst (const tree cst) 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) { @@ -1490,14 +1553,9 @@ write_integer_cst (const tree cst) 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 ()); } } @@ -1524,45 +1582,29 @@ write_integer_cst (const tree cst) 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); } } @@ -1584,25 +1626,21 @@ write_identifier (const char *identifier) ::= 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"); } } @@ -1612,11 +1650,7 @@ write_special_name_constructor (const tree ctor) ::= 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) @@ -1625,14 +1659,14 @@ 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"); } } @@ -1649,7 +1683,7 @@ local_class_index (tree entity) tree ctx = TYPE_CONTEXT (entity); for (ix = 0; ; ix++) { - tree type = VEC_index (tree, local_classes, ix); + tree type = (*local_classes)[ix]; if (type == entity) return discriminator; if (TYPE_CONTEXT (type) == ctx @@ -1696,8 +1730,8 @@ discriminator_for_local_entity (tree entity) string literals used in FUNCTION. */ static int -discriminator_for_string_literal (tree function ATTRIBUTE_UNUSED, - tree string ATTRIBUTE_UNUSED) +discriminator_for_string_literal (tree /*function*/, + tree /*string*/) { /* For now, we don't discriminate amongst string literals. */ return 0; @@ -1828,7 +1862,23 @@ write_type (tree type) 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 @@ -1840,6 +1890,9 @@ write_type (tree type) /* 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 @@ -1847,7 +1900,7 @@ write_type (tree type) if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type)) type = TREE_TYPE (first_field (type)); - if (TYPE_PTRMEM_P (type)) + if (TYPE_PTRDATAMEM_P (type)) write_pointer_to_member_type (type); else { @@ -1860,7 +1913,7 @@ write_type (tree type) 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) @@ -1914,7 +1967,7 @@ write_type (tree 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'); @@ -1927,14 +1980,29 @@ write_type (tree type) 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)) + { + if (AUTO_IS_DECLTYPE (type)) + write_identifier ("Dc"); + else + write_identifier ("Da"); + ++is_builtin_type; + break; + } + /* else fall through. */ case TEMPLATE_PARM_INDEX: write_template_param (type); break; @@ -1959,10 +2027,9 @@ write_type (tree type) 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; @@ -1977,8 +2044,7 @@ write_type (tree type) && !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; @@ -1999,9 +2065,13 @@ write_type (tree type) 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; + } } } @@ -2018,6 +2088,10 @@ write_type (tree type) case NULLPTR_TYPE: 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: @@ -2266,7 +2340,7 @@ write_builtin_type (tree type) METHOD_TYPE. The return type is mangled before the parameter types. - ::= F [Y] E */ + ::= F [Y] [] E */ static void write_function_type (const tree type) @@ -2299,6 +2373,13 @@ 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'); } @@ -2458,7 +2539,7 @@ write_template_args (tree args) 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); @@ -2494,13 +2575,17 @@ write_expression (tree expr) 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); code = TREE_CODE (expr); } - if (code == BASELINK) + if (code == BASELINK + && (!type_unknown_p (expr) + || !BASELINK_QUALIFIED_P (expr))) { expr = BASELINK_FUNCTIONS (expr); code = TREE_CODE (expr); @@ -2526,7 +2611,7 @@ write_expression (tree expr) 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)) { @@ -2555,7 +2640,7 @@ write_expression (tree expr) write_char ('L'); write_unsigned_number (delta - 1); } - else + if (abi_version_crosses (5)) G.need_abi_warning = true; } write_char ('p'); @@ -2563,15 +2648,17 @@ write_expression (tree expr) } 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'); } else if (TREE_CODE (expr) == SIZEOF_EXPR + && SIZEOF_EXPR_TYPE_P (expr)) + { + write_string ("st"); + write_type (TREE_TYPE (TREE_OPERAND (expr, 0))); + } + else if (TREE_CODE (expr) == SIZEOF_EXPR && TYPE_P (TREE_OPERAND (expr, 0))) { write_string ("st"); @@ -2583,19 +2670,19 @@ write_expression (tree expr) write_string ("at"); write_type (TREE_OPERAND (expr, 0)); } - else if (TREE_CODE (expr) == SCOPE_REF) + else if (code == SCOPE_REF + || code == BASELINK) { - tree scope = TREE_OPERAND (expr, 0); - tree member = TREE_OPERAND (expr, 1); - - if (!abi_version_at_least (2) && DECL_P (member)) + tree scope, member; + if (code == SCOPE_REF) { - 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); + scope = TREE_OPERAND (expr, 0); + member = TREE_OPERAND (expr, 1); + } + else + { + scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (expr)); + member = BASELINK_FUNCTIONS (expr); } /* If the MEMBER is a real declaration, then the qualifying @@ -2603,7 +2690,7 @@ write_expression (tree expr) 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 { @@ -2612,13 +2699,13 @@ write_expression (tree expr) 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 @@ -2685,14 +2772,13 @@ write_expression (tree expr) 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'); @@ -2724,7 +2810,7 @@ write_expression (tree expr) } else if (code == CONSTRUCTOR) { - VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr); + vec *elts = CONSTRUCTOR_ELTS (expr); unsigned i; tree val; if (BRACE_ENCLOSED_INITIALIZER_P (expr)) @@ -2773,11 +2859,16 @@ write_expression (tree expr) { 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; } @@ -2786,17 +2877,28 @@ write_expression (tree expr) 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) { - sorry ("mangling %C", code); + switch (code) + { + case TRAIT_EXPR: + error ("use of built-in trait %qE in function signature; " + "use library traits instead", expr); + break; + + default: + sorry ("mangling %C", code); + break; + } return; } else @@ -2852,7 +2954,7 @@ write_expression (tree expr) case PREDECREMENT_EXPR: if (abi_version_at_least (6)) write_char ('_'); - else + if (abi_version_crosses (6)) G.need_abi_warning = 1; /* Fall through. */ @@ -2915,6 +3017,25 @@ write_template_arg_literal (const tree value) write_real_cst (value); break; + case COMPLEX_CST: + if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST + && TREE_CODE (TREE_IMAGPART (value)) == INTEGER_CST) + { + write_integer_cst (TREE_REALPART (value)); + write_char ('_'); + write_integer_cst (TREE_IMAGPART (value)); + } + else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST + && TREE_CODE (TREE_IMAGPART (value)) == REAL_CST) + { + write_real_cst (TREE_REALPART (value)); + write_char ('_'); + write_real_cst (TREE_IMAGPART (value)); + } + else + gcc_unreachable (); + break; + case STRING_CST: sorry ("string literal in function template signature"); break; @@ -2960,10 +3081,7 @@ write_template_arg (tree node) 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 @@ -2971,7 +3089,7 @@ write_template_arg (tree node) { 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; } @@ -2984,10 +3102,9 @@ write_template_arg (tree node) 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'); @@ -2998,25 +3115,20 @@ write_template_arg (tree node) /* 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'); } @@ -3071,21 +3183,16 @@ write_array_type (const tree type) { /* The ABI specifies that we should mangle the number of elements in the array, not the largest allowed index. */ - max = size_binop (PLUS_EXPR, max, size_one_node); - write_unsigned_number (tree_low_cst (max, 1)); + offset_int wmax = wi::to_offset (max) + 1; + /* Truncate the result - this will mangle [0, SIZE_INT_MAX] + number of elements as zero. */ + 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); } @@ -3202,15 +3309,10 @@ start_mangling (const tree entity) 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_truncate (tree, G.substitutions, 0); + vec_safe_truncate (G.substitutions, 0); /* Null-terminate the string. */ write_char ('\0'); @@ -3220,18 +3322,18 @@ finish_mangling_internal (const bool warn) /* 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)); @@ -3244,7 +3346,7 @@ init_mangle (void) { gcc_obstack_init (&name_obstack); name_base = obstack_alloc (&name_obstack, 0); - G.substitutions = NULL; + vec_alloc (G.substitutions, 0); /* Cache these identifiers for quick comparison when checking for standard substitutions. */ @@ -3289,7 +3391,7 @@ mangle_decl_string (const tree decl) 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)); @@ -3318,43 +3420,83 @@ get_mangled_id (tree decl) void mangle_decl (const tree decl) { - tree id = get_mangled_id (decl); + tree id; + bool dep; + + /* Don't bother mangling uninstantiated templates. */ + ++processing_template_decl; + if (TREE_CODE (decl) == TYPE_DECL) + dep = dependent_type_p (TREE_TYPE (decl)); + else + dep = (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) + && any_dependent_template_arguments_p (DECL_TI_ARGS (decl))); + --processing_template_decl; + if (dep) + return; + + id = get_mangled_id (decl); SET_DECL_ASSEMBLER_NAME (decl, id); 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 } } @@ -3368,7 +3510,7 @@ mangle_type_string (const tree type) 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; @@ -3393,7 +3535,7 @@ mangle_special_for_type (const tree type, const char *code) /* 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", @@ -3464,7 +3606,7 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo) 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)); @@ -3543,32 +3685,38 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset, /* 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 +{ + 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_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 @@ -3578,25 +3726,25 @@ compare_type (const void *val1, const void *val2) 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::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; @@ -3612,6 +3760,21 @@ mangle_conv_op_name_for_type (const tree type) return identifier; } +/* Write out the appropriate string for this variable when generating + another mangled name based on this one. */ + +static void +write_guarded_var_name (const tree variable) +{ + 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); + else + write_name (variable, /*ignore_local_scope=*/0); +} + /* Return an identifier for the name of an initialization guard variable for indicated VARIABLE. */ @@ -3620,13 +3783,46 @@ mangle_guard_variable (const tree variable) { start_mangling (variable); write_string ("_ZGV"); - if (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); - else - write_name (variable, /*ignore_local_scope=*/0); - return finish_mangling_get_identifier (/*warn=*/false); + write_guarded_var_name (variable); + return finish_mangling_get_identifier (); +} + +/* Return an identifier for the name of a thread_local initialization + function for VARIABLE. */ + +tree +mangle_tls_init_fn (const tree variable) +{ + start_mangling (variable); + write_string ("_ZTH"); + write_guarded_var_name (variable); + return finish_mangling_get_identifier (); +} + +/* Return an identifier for the name of a thread_local wrapper + function for VARIABLE. */ + +#define TLS_WRAPPER_PREFIX "_ZTW" + +tree +mangle_tls_wrapper_fn (const tree variable) +{ + start_mangling (variable); + write_string (TLS_WRAPPER_PREFIX); + write_guarded_var_name (variable); + return finish_mangling_get_identifier (); +} + +/* Return true iff FN is a thread_local wrapper function. */ + +bool +decl_tls_wrapper_p (const tree fn) +{ + if (TREE_CODE (fn) != FUNCTION_DECL) + return false; + tree name = DECL_NAME (fn); + return strncmp (IDENTIFIER_POINTER (name), TLS_WRAPPER_PREFIX, + strlen (TLS_WRAPPER_PREFIX)) == 0; } /* Return an identifier for the name of a temporary variable used to @@ -3644,7 +3840,7 @@ mangle_ref_init_variable (const tree variable) /* 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 (); } @@ -3671,4 +3867,34 @@ write_java_integer_type_codes (const tree type) 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::__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"