/* Name mangling for the 3.0 -*- C++ -*- ABI.
- Copyright (C) 2000-2018 Free Software Foundation, Inc.
+ Copyright (C) 2000-2020 Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com>
This file is part of GCC.
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)
+ if (FUNC_OR_METHOD_TYPE_P (node))
{
node = build_ref_qualified_type (node, type_memfn_rqual (orig));
tree r = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (orig));
else if (template_type_parameter_p (decl))
/* template type parms have no mangling context. */
return NULL_TREE;
- return CP_DECL_CONTEXT (decl);
+
+ tcontext = CP_DECL_CONTEXT (decl);
+
+ /* Ignore the artificial declare reduction functions. */
+ if (tcontext
+ && TREE_CODE (tcontext) == FUNCTION_DECL
+ && DECL_OMP_DECLARE_REDUCTION_P (tcontext))
+ return decl_mangling_context (tcontext);
+
+ return tcontext;
}
/* <name> ::= <unscoped-name>
type = TREE_TYPE (fn_type);
}
else if (FNDECL_USED_AUTO (decl))
- type = (DECL_STRUCT_FUNCTION (decl)->language
- ->x_auto_return_pattern);
+ type = DECL_SAVED_AUTO_RETURN_TYPE (decl);
else
type = DECL_CONV_FN_TYPE (decl);
write_conversion_operator_name (type);
release_tree_vector (vec);
}
-/* Simplified unique_ptr clone to release a tree vec on exit. */
-
-struct releasing_vec
-{
- typedef vec<tree, va_gc> vec_t;
-
- releasing_vec (vec_t *v): v(v) { }
- releasing_vec (): v(make_tree_vector ()) { }
-
- /* Copy constructor is deliberately declared but not defined,
- copies must always be elided. */
- releasing_vec (const releasing_vec &);
-
- vec_t &operator* () const { return *v; }
- vec_t *operator-> () const { return v; }
- vec_t *get () const { return v; }
- operator vec_t *() const { return v; }
- tree& operator[] (unsigned i) const { return (*v)[i]; }
-
- ~releasing_vec() { release_tree_vector (v); }
-private:
- vec_t *v;
-};
-
/* True iff the TREE_LISTS T1 and T2 of ABI tags are equivalent. */
static bool
write_name (entity, /*ignore_local_scope=*/1);
if (DECL_DISCRIMINATOR_P (local_entity)
&& !(TREE_CODE (local_entity) == TYPE_DECL
- && (LAMBDA_TYPE_P (TREE_TYPE (local_entity))
- || TYPE_UNNAMED_P (TREE_TYPE (local_entity)))))
+ && TYPE_ANON_P (TREE_TYPE (local_entity))))
write_discriminator (discriminator_for_local_entity (local_entity));
}
}
t = cp_build_type_attribute_variant (t, attrs);
}
gcc_assert (t != type);
- if (TREE_CODE (t) == FUNCTION_TYPE
- || TREE_CODE (t) == METHOD_TYPE)
+ if (FUNC_OR_METHOD_TYPE_P (t))
{
t = build_ref_qualified_type (t, type_memfn_rqual (type));
if (flag_noexcept_type)
/* See through any typedefs. */
type = TYPE_MAIN_VARIANT (type);
- if (TREE_CODE (type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE)
+ if (FUNC_OR_METHOD_TYPE_P (type))
type = cxx_copy_lang_qualifiers (type, type_orig);
/* According to the C++ ABI, some library classes are passed the
break;
case TYPEOF_TYPE:
- sorry ("mangling typeof, use decltype instead");
+ sorry ("mangling %<typeof%>, use %<decltype%> instead");
break;
case UNDERLYING_TYPE:
- sorry ("mangling __underlying_type");
+ sorry ("mangling %<__underlying_type%>");
break;
case LANG_TYPE:
break;
case INTEGER_TYPE:
- /* TYPE may still be wchar_t, char16_t, or char32_t, since that
+ /* TYPE may still be wchar_t, char8_t, char16_t, or char32_t, since that
isn't in integer_type_nodes. */
if (type == wchar_type_node)
write_char ('w');
+ else if (type == char8_type_node)
+ write_string ("Du");
else if (type == char16_type_node)
write_string ("Ds");
else if (type == char32_type_node)
{
enum tree_code code = TREE_CODE (expr);
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ {
+ expr = TARGET_EXPR_INITIAL (expr);
+ code = TREE_CODE (expr);
+ }
+
/* Skip NOP_EXPR and CONVERT_EXPR. They can occur when (say) a pointer
argument is converted (via qualification conversions) to another type. */
while (CONVERT_EXPR_CODE_P (code)
|| location_wrapper_p (expr)
/* Parentheses aren't mangled. */
|| code == PAREN_EXPR
- || code == NON_LVALUE_EXPR)
+ || code == NON_LVALUE_EXPR
+ || (code == VIEW_CONVERT_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 0)) == TEMPLATE_PARM_INDEX))
{
expr = TREE_OPERAND (expr, 0);
code = TREE_CODE (expr);
{
scope = TREE_OPERAND (expr, 0);
member = TREE_OPERAND (expr, 1);
- gcc_assert (!BASELINK_P (member));
+ if (BASELINK_P (member))
+ member = BASELINK_FUNCTIONS (member);
}
else
{
}
else if (code == CONSTRUCTOR)
{
- vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
- unsigned i; tree val;
+ bool braced_init = BRACE_ENCLOSED_INITIALIZER_P (expr);
+ tree etype = TREE_TYPE (expr);
- if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ if (braced_init)
write_string ("il");
else
{
write_string ("tl");
- write_type (TREE_TYPE (expr));
+ write_type (etype);
+ }
+
+ if (!initializer_zerop (expr) || !trivial_type_p (etype))
+ {
+ /* Convert braced initializer lists to STRING_CSTs so that
+ A<"Foo"> mangles the same as A<{'F', 'o', 'o', 0}> while
+ still using the latter mangling for strings that
+ originated as braced initializer lists. */
+ expr = braced_lists_to_strings (etype, expr);
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
+ unsigned last_nonzero = -1, i;
+ tree val;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+ if (!initializer_zerop (val))
+ last_nonzero = i;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+ {
+ if (i > last_nonzero)
+ break;
+ write_expression (val);
+ }
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (expr) == STRING_CST);
+ write_expression (expr);
+ }
}
- FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
- write_expression (val);
+ write_char ('E');
+ }
+ else if (code == LAMBDA_EXPR)
+ {
+ /* [temp.over.link] Two lambda-expressions are never considered
+ equivalent.
+
+ So just use the closure type mangling. */
+ write_string ("tl");
+ write_type (LAMBDA_EXPR_CLOSURE (expr));
write_char ('E');
}
else if (dependent_name (expr))
/* Mangle a dependent name as the name, not whatever happens to
be the first function in the overload set. */
- if ((TREE_CODE (fn) == FUNCTION_DECL
- || TREE_CODE (fn) == OVERLOAD)
+ if (OVL_P (fn)
&& type_dependent_expression_p_push (expr))
fn = OVL_NAME (fn);
static void
write_template_arg_literal (const tree value)
{
- write_char ('L');
- write_type (TREE_TYPE (value));
+ if (TREE_CODE (value) == STRING_CST)
+ /* Temporarily mangle strings as braced initializer lists. */
+ write_string ("tl");
+ else
+ write_char ('L');
+
+ tree valtype = TREE_TYPE (value);
+ write_type (valtype);
/* Write a null member pointer value as (type)0, regardless of its
real representation. */
case INTEGER_CST:
gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
|| integer_zerop (value) || integer_onep (value));
- write_integer_cst (value);
+ if (!(abi_version_at_least (14)
+ && NULLPTR_TYPE_P (TREE_TYPE (value))))
+ write_integer_cst (value);
break;
case REAL_CST:
break;
case STRING_CST:
- sorry ("string literal in function template signature");
- break;
+ {
+ /* Mangle strings the same as braced initializer lists. */
+ unsigned n = TREE_STRING_LENGTH (value);
+ const char *str = TREE_STRING_POINTER (value);
+
+ /* Count the number of trailing nuls and subtract them from
+ STRSIZE because they don't need to be mangled. */
+ for (const char *p = str + n - 1; ; --p)
+ {
+ if (*p || p == str)
+ {
+ n -= str + n - !!*p - p;
+ break;
+ }
+ }
+ tree eltype = TREE_TYPE (valtype);
+ for (const char *p = str; n--; ++p)
+ {
+ write_char ('L');
+ write_type (eltype);
+ write_unsigned_number (*(const unsigned char*)p);
+ write_string ("E");
+ }
+ break;
+ }
default:
gcc_unreachable ();
}
}
+ if (template_parm_object_p (node))
+ /* We want to mangle the argument, not the var we stored it in. */
+ node = DECL_INITIAL (node);
+
/* Strip a conversion added by convert_nontype_argument. */
if (TREE_CODE (node) == IMPLICIT_CONV_EXPR)
node = TREE_OPERAND (node, 0);
mangle_decl_string (const tree decl)
{
tree result;
- location_t saved_loc = input_location;
tree saved_fn = NULL_TREE;
bool template_p = false;
current_function_decl = NULL_TREE;
}
}
- input_location = DECL_SOURCE_LOCATION (decl);
+ iloc_sentinel ils (DECL_SOURCE_LOCATION (decl));
start_mangling (decl);
pop_tinst_level ();
current_function_decl = saved_fn;
}
- input_location = saved_loc;
return result;
}
if (for_decl && DECL_THUNK_P (for_decl))
warning_at (DECL_SOURCE_LOCATION (t), OPT_Wabi,
"the mangled name of a thunk for %qD changes between "
- "-fabi-version=%d and -fabi-version=%d",
+ "%<-fabi-version=%d%> and %<-fabi-version=%d%>",
t, flag_abi_version, warn_abi_version);
else if (for_decl)
warning_at (DECL_SOURCE_LOCATION (for_decl), OPT_Wabi,
"the mangled name of %qD changes between "
- "-fabi-version=%d and -fabi-version=%d",
+ "%<-fabi-version=%d%> and %<-fabi-version=%d%>",
for_decl, flag_abi_version, warn_abi_version);
else
warning_at (DECL_SOURCE_LOCATION (t), OPT_Wabi,
"the mangled name of the initialization guard variable "
- "for %qD changes between -fabi-version=%d and "
- "-fabi-version=%d",
+ "for %qD changes between %<-fabi-version=%d%> and "
+ "%<-fabi-version=%d%>",
t, flag_abi_version, warn_abi_version);
}
}
}
/* Return an identifier for the name of a temporary variable used to
- initialize a static reference. This isn't part of the ABI, but we might
- as well call them something readable. */
-
-static GTY(()) int temp_count;
+ initialize a static reference. This is now part of the ABI. */
tree
mangle_ref_init_variable (const tree variable)
write_name (variable, /*ignore_local_scope=*/0);
/* Avoid name clashes with aggregate initialization of multiple
references at once. */
- write_unsigned_number (temp_count++);
+ write_compact_number (current_ref_temp_count++);
+ return finish_mangling_get_identifier ();
+}
+
+/* Return an identifier for the mangled name of a C++20 template parameter
+ object for template argument EXPR. */
+
+tree
+mangle_template_parm_object (tree expr)
+{
+ start_mangling (expr);
+ write_string ("_ZTAX");
+ write_expression (expr);
+ write_char ('E');
return finish_mangling_get_identifier ();
}
\f