mirror of git://gcc.gnu.org/git/gcc.git
Adjust mangling of ABI tags on class template member functions.
* class.c (missing_abi_tags): New. (check_abi_tags): Don't check template. Add just_checking mode. * mangle.c (abi_flag_at_least, any_abi_below, equal_abi_tags): New. (sorted_abi_tags): Split out from write_abi_tags. (struct releasing_vec): New. (write_unqualified_name): Only look for the primary template for types. Implement backward compatibility. From-SVN: r239298
This commit is contained in:
parent
f0bc3323eb
commit
7ab8c6470c
|
|
@ -1,5 +1,14 @@
|
||||||
2016-08-09 Jason Merrill <jason@redhat.com>
|
2016-08-09 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Adjust mangling of ABI tags on class template member functions.
|
||||||
|
* class.c (missing_abi_tags): New.
|
||||||
|
(check_abi_tags): Don't check template. Add just_checking mode.
|
||||||
|
* mangle.c (abi_flag_at_least, any_abi_below, equal_abi_tags): New.
|
||||||
|
(sorted_abi_tags): Split out from write_abi_tags.
|
||||||
|
(struct releasing_vec): New.
|
||||||
|
(write_unqualified_name): Only look for the primary
|
||||||
|
template for types. Implement backward compatibility.
|
||||||
|
|
||||||
PR c++/72849
|
PR c++/72849
|
||||||
* constexpr.c (cxx_eval_constant_expression): Check
|
* constexpr.c (cxx_eval_constant_expression): Check
|
||||||
COMPLETE_TYPE_P before calling is_really_empty_class.
|
COMPLETE_TYPE_P before calling is_really_empty_class.
|
||||||
|
|
|
||||||
|
|
@ -1561,20 +1561,20 @@ mark_abi_tags (tree t, bool val)
|
||||||
|
|
||||||
/* Check that T has all the ABI tags that subobject SUBOB has, or
|
/* Check that T has all the ABI tags that subobject SUBOB has, or
|
||||||
warn if not. If T is a (variable or function) declaration, also
|
warn if not. If T is a (variable or function) declaration, also
|
||||||
add any missing tags. */
|
return any missing tags, and add them to T if JUST_CHECKING is false. */
|
||||||
|
|
||||||
static void
|
static tree
|
||||||
check_abi_tags (tree t, tree subob)
|
check_abi_tags (tree t, tree subob, bool just_checking = false)
|
||||||
{
|
{
|
||||||
bool inherit = DECL_P (t);
|
bool inherit = DECL_P (t);
|
||||||
|
|
||||||
if (!inherit && !warn_abi_tag)
|
if (!inherit && !warn_abi_tag)
|
||||||
return;
|
return NULL_TREE;
|
||||||
|
|
||||||
tree decl = TYPE_P (t) ? TYPE_NAME (t) : t;
|
tree decl = TYPE_P (t) ? TYPE_NAME (t) : t;
|
||||||
if (!TREE_PUBLIC (decl))
|
if (!TREE_PUBLIC (decl))
|
||||||
/* No need to worry about things local to this TU. */
|
/* No need to worry about things local to this TU. */
|
||||||
return;
|
return NULL_TREE;
|
||||||
|
|
||||||
mark_abi_tags (t, true);
|
mark_abi_tags (t, true);
|
||||||
|
|
||||||
|
|
@ -1585,7 +1585,15 @@ check_abi_tags (tree t, tree subob)
|
||||||
|
|
||||||
cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
|
cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
|
||||||
|
|
||||||
if (inherit && data.tags)
|
if (!(inherit && data.tags))
|
||||||
|
/* We don't need to do anything with data.tags. */;
|
||||||
|
else if (just_checking)
|
||||||
|
for (tree t = data.tags; t; t = TREE_CHAIN (t))
|
||||||
|
{
|
||||||
|
tree id = get_identifier (TREE_STRING_POINTER (TREE_VALUE (t)));
|
||||||
|
IDENTIFIER_MARKED (id) = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
|
tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
|
||||||
if (attr)
|
if (attr)
|
||||||
|
|
@ -1597,6 +1605,8 @@ check_abi_tags (tree t, tree subob)
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_abi_tags (t, false);
|
mark_abi_tags (t, false);
|
||||||
|
|
||||||
|
return data.tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that DECL has all the ABI tags that are used in parts of its type
|
/* Check that DECL has all the ABI tags that are used in parts of its type
|
||||||
|
|
@ -1605,15 +1615,6 @@ check_abi_tags (tree t, tree subob)
|
||||||
void
|
void
|
||||||
check_abi_tags (tree decl)
|
check_abi_tags (tree decl)
|
||||||
{
|
{
|
||||||
tree t;
|
|
||||||
if (abi_version_at_least (10)
|
|
||||||
&& DECL_LANG_SPECIFIC (decl)
|
|
||||||
&& DECL_USE_TEMPLATE (decl)
|
|
||||||
&& (t = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)),
|
|
||||||
t != decl))
|
|
||||||
/* Make sure that our template has the appropriate tags, since
|
|
||||||
write_unqualified_name looks for them there. */
|
|
||||||
check_abi_tags (t);
|
|
||||||
if (VAR_P (decl))
|
if (VAR_P (decl))
|
||||||
check_abi_tags (decl, TREE_TYPE (decl));
|
check_abi_tags (decl, TREE_TYPE (decl));
|
||||||
else if (TREE_CODE (decl) == FUNCTION_DECL
|
else if (TREE_CODE (decl) == FUNCTION_DECL
|
||||||
|
|
@ -1621,6 +1622,22 @@ check_abi_tags (tree decl)
|
||||||
check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)));
|
check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return any ABI tags that are used in parts of the type of DECL
|
||||||
|
that are not reflected in its mangled name. This function is only
|
||||||
|
used in backward-compatible mangling for ABI <11. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
missing_abi_tags (tree decl)
|
||||||
|
{
|
||||||
|
if (VAR_P (decl))
|
||||||
|
return check_abi_tags (decl, TREE_TYPE (decl), true);
|
||||||
|
else if (TREE_CODE (decl) == FUNCTION_DECL
|
||||||
|
&& !mangle_return_type_p (decl))
|
||||||
|
return check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)), true);
|
||||||
|
else
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
inherit_targ_abi_tags (tree t)
|
inherit_targ_abi_tags (tree t)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5686,6 +5686,7 @@ extern void inherit_targ_abi_tags (tree);
|
||||||
extern void defaulted_late_check (tree);
|
extern void defaulted_late_check (tree);
|
||||||
extern bool defaultable_fn_check (tree);
|
extern bool defaultable_fn_check (tree);
|
||||||
extern void check_abi_tags (tree);
|
extern void check_abi_tags (tree);
|
||||||
|
extern tree missing_abi_tags (tree);
|
||||||
extern void fixup_type_variants (tree);
|
extern void fixup_type_variants (tree);
|
||||||
extern void fixup_attribute_variants (tree);
|
extern void fixup_attribute_variants (tree);
|
||||||
extern tree* decl_cloned_function_p (const_tree, bool);
|
extern tree* decl_cloned_function_p (const_tree, bool);
|
||||||
|
|
|
||||||
122
gcc/cp/mangle.c
122
gcc/cp/mangle.c
|
|
@ -91,6 +91,14 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#define abi_warn_or_compat_version_crosses(N) \
|
#define abi_warn_or_compat_version_crosses(N) \
|
||||||
(abi_version_crosses (N) || abi_compat_version_crosses (N))
|
(abi_version_crosses (N) || abi_compat_version_crosses (N))
|
||||||
|
|
||||||
|
/* And sometimes we can simplify the code path if we don't need to worry about
|
||||||
|
previous ABIs. */
|
||||||
|
#define abi_flag_at_least(flag,N) (flag == 0 || flag >= N)
|
||||||
|
#define any_abi_below(N) \
|
||||||
|
(!abi_version_at_least (N) \
|
||||||
|
|| !abi_flag_at_least (warn_abi_version, (N)) \
|
||||||
|
|| !abi_flag_at_least (flag_abi_compat_version, (N)))
|
||||||
|
|
||||||
/* Things we only need one of. This module is not reentrant. */
|
/* Things we only need one of. This module is not reentrant. */
|
||||||
struct GTY(()) globals {
|
struct GTY(()) globals {
|
||||||
/* An array of the current substitution candidates, in the order
|
/* An array of the current substitution candidates, in the order
|
||||||
|
|
@ -224,6 +232,7 @@ static void dump_substitution_candidates (void);
|
||||||
static tree mangle_decl_string (const tree);
|
static tree mangle_decl_string (const tree);
|
||||||
static int local_class_index (tree);
|
static int local_class_index (tree);
|
||||||
static void maybe_check_abi_tags (tree, tree = NULL_TREE);
|
static void maybe_check_abi_tags (tree, tree = NULL_TREE);
|
||||||
|
static bool equal_abi_tags (tree, tree);
|
||||||
|
|
||||||
/* Control functions. */
|
/* Control functions. */
|
||||||
|
|
||||||
|
|
@ -1329,16 +1338,52 @@ write_unqualified_name (tree decl)
|
||||||
write_source_name (DECL_NAME (decl));
|
write_source_name (DECL_NAME (decl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We use the ABI tags from the primary template, ignoring tags on any
|
/* We use the ABI tags from the primary class template, ignoring tags on any
|
||||||
specializations. This is necessary because C++ doesn't require a
|
specializations. This is necessary because C++ doesn't require a
|
||||||
specialization to be declared before it is used unless the use
|
specialization to be declared before it is used unless the use requires a
|
||||||
requires a complete type, but we need to get the tags right on
|
complete type, but we need to get the tags right on incomplete types as
|
||||||
incomplete types as well. */
|
well. */
|
||||||
if (tree tmpl = most_general_template (decl))
|
if (tree tmpl = most_general_template (decl))
|
||||||
decl = DECL_TEMPLATE_RESULT (tmpl);
|
{
|
||||||
/* Don't crash on an unbound class template. */
|
tree res = DECL_TEMPLATE_RESULT (tmpl);
|
||||||
if (decl && TREE_CODE (decl) != NAMESPACE_DECL)
|
if (res == NULL_TREE)
|
||||||
write_abi_tags (get_abi_tags (decl));
|
/* UNBOUND_CLASS_TEMPLATE. */;
|
||||||
|
else if (DECL_DECLARES_TYPE_P (decl))
|
||||||
|
decl = res;
|
||||||
|
else if (any_abi_below (11))
|
||||||
|
{
|
||||||
|
/* ABI v10 implicit tags on the template. */
|
||||||
|
tree mtags = missing_abi_tags (res);
|
||||||
|
/* Explicit tags on the template. */
|
||||||
|
tree ttags = get_abi_tags (res);
|
||||||
|
/* Tags on the instantiation. */
|
||||||
|
tree dtags = get_abi_tags (decl);
|
||||||
|
|
||||||
|
if (mtags && abi_warn_or_compat_version_crosses (10))
|
||||||
|
G.need_abi_warning = 1;
|
||||||
|
|
||||||
|
/* Add the v10 tags to the explicit tags now. */
|
||||||
|
mtags = chainon (mtags, ttags);
|
||||||
|
|
||||||
|
if (!G.need_abi_warning
|
||||||
|
&& abi_warn_or_compat_version_crosses (11)
|
||||||
|
&& !equal_abi_tags (dtags, mtags))
|
||||||
|
G.need_abi_warning = 1;
|
||||||
|
|
||||||
|
if (!abi_version_at_least (10))
|
||||||
|
/* In abi <10, we only got the explicit tags. */
|
||||||
|
decl = res;
|
||||||
|
else if (flag_abi_version == 10)
|
||||||
|
{
|
||||||
|
/* In ABI 10, we want explict and implicit tags. */
|
||||||
|
write_abi_tags (mtags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree tags = get_abi_tags (decl);
|
||||||
|
write_abi_tags (tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the unqualified-name for a conversion operator to TYPE. */
|
/* Write the unqualified-name for a conversion operator to TYPE. */
|
||||||
|
|
@ -1381,15 +1426,11 @@ tree_string_cmp (const void *p1, const void *p2)
|
||||||
TREE_STRING_POINTER (s2));
|
TREE_STRING_POINTER (s2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ID is the name of a function or type with abi_tags attribute TAGS.
|
/* Return the TREE_LIST of TAGS as a sorted VEC. */
|
||||||
Write out the name, suitably decorated. */
|
|
||||||
|
|
||||||
static void
|
static vec<tree, va_gc> *
|
||||||
write_abi_tags (tree tags)
|
sorted_abi_tags (tree tags)
|
||||||
{
|
{
|
||||||
if (tags == NULL_TREE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vec<tree, va_gc> * vec = make_tree_vector();
|
vec<tree, va_gc> * vec = make_tree_vector();
|
||||||
|
|
||||||
for (tree t = tags; t; t = TREE_CHAIN (t))
|
for (tree t = tags; t; t = TREE_CHAIN (t))
|
||||||
|
|
@ -1402,6 +1443,20 @@ write_abi_tags (tree tags)
|
||||||
|
|
||||||
vec->qsort (tree_string_cmp);
|
vec->qsort (tree_string_cmp);
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
vec<tree, va_gc> * vec = sorted_abi_tags (tags);
|
||||||
|
|
||||||
unsigned i; tree str;
|
unsigned i; tree str;
|
||||||
FOR_EACH_VEC_ELT (*vec, i, str)
|
FOR_EACH_VEC_ELT (*vec, i, str)
|
||||||
{
|
{
|
||||||
|
|
@ -1413,6 +1468,43 @@ write_abi_tags (tree tags)
|
||||||
release_tree_vector (vec);
|
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 ()) { }
|
||||||
|
|
||||||
|
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
|
||||||
|
equal_abi_tags (tree t1, tree t2)
|
||||||
|
{
|
||||||
|
releasing_vec v1 = sorted_abi_tags (t1);
|
||||||
|
releasing_vec v2 = sorted_abi_tags (t2);
|
||||||
|
|
||||||
|
unsigned len1 = v1->length();
|
||||||
|
if (len1 != v2->length())
|
||||||
|
return false;
|
||||||
|
for (unsigned i = 0; i < len1; ++i)
|
||||||
|
if (tree_string_cmp (v1[i], v2[i]) != 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write a user-defined literal operator.
|
/* Write a user-defined literal operator.
|
||||||
::= li <source-name> # "" <source-name>
|
::= li <source-name> # "" <source-name>
|
||||||
IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */
|
IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// { dg-do compile { target c++11 } }
|
||||||
|
// { dg-options -Wabi=10 }
|
||||||
|
|
||||||
|
struct [[gnu::abi_tag ("foo")]] A
|
||||||
|
{
|
||||||
|
template <class T> static T f();
|
||||||
|
template <class T> static A g();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> struct B
|
||||||
|
{
|
||||||
|
static decltype(A::f<T>()) fa(decltype(A::f<T>()));
|
||||||
|
static decltype(A::f<T>()) fv(); // { dg-warning "mangled name" }
|
||||||
|
static decltype(A::g<T>()) ga(decltype(A::g<T>()));
|
||||||
|
static decltype(A::g<T>()) gv();
|
||||||
|
template <class U>
|
||||||
|
static decltype(A::f<U>()) hv();
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
B<int>::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } }
|
||||||
|
B<int>::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvEv" } }
|
||||||
|
B<int>::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } }
|
||||||
|
B<int>::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvB3fooEv" } }
|
||||||
|
B<int>::hv<int>(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// { dg-do compile { target c++11 } }
|
||||||
|
// { dg-options "-fabi-version=10 -Wabi" }
|
||||||
|
|
||||||
|
struct [[gnu::abi_tag ("foo")]] A
|
||||||
|
{
|
||||||
|
template <class T> static T f();
|
||||||
|
template <class T> static A g();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> struct B
|
||||||
|
{
|
||||||
|
static decltype(A::f<T>()) fa(decltype(A::f<T>()));
|
||||||
|
static decltype(A::f<T>()) fv(); // { dg-warning "mangled name" }
|
||||||
|
static decltype(A::g<T>()) ga(decltype(A::g<T>()));
|
||||||
|
static decltype(A::g<T>()) gv();
|
||||||
|
template <class U>
|
||||||
|
static decltype(A::f<U>()) hv();
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
B<int>::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } }
|
||||||
|
B<int>::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvB3fooEv" } }
|
||||||
|
B<int>::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } }
|
||||||
|
B<int>::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvB3fooEv" } }
|
||||||
|
B<int>::hv<int>(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// { dg-do compile { target c++11 } }
|
||||||
|
// { dg-options "-fabi-version=9 -Wabi" }
|
||||||
|
|
||||||
|
struct [[gnu::abi_tag ("foo")]] A
|
||||||
|
{
|
||||||
|
template <class T> static T f();
|
||||||
|
template <class T> static A g();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> struct B
|
||||||
|
{
|
||||||
|
static decltype(A::f<T>()) fa(decltype(A::f<T>()));
|
||||||
|
static decltype(A::f<T>()) fv();
|
||||||
|
static decltype(A::g<T>()) ga(decltype(A::g<T>()));
|
||||||
|
static decltype(A::g<T>()) gv(); // { dg-warning "mangled name" }
|
||||||
|
template <class U>
|
||||||
|
static decltype(A::f<U>()) hv();
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
B<int>::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } }
|
||||||
|
B<int>::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvEv" } }
|
||||||
|
B<int>::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } }
|
||||||
|
B<int>::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvEv" } }
|
||||||
|
B<int>::hv<int>(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } }
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue