From: Jason Merrill Date: Tue, 9 Aug 2016 16:55:01 +0000 (-0400) Subject: Adjust mangling of ABI tags on class template member functions. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7ab8c6470c6275fd9e58038f1dd3e8744bebe2bc;p=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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ffb0b85e003..81ca1a1b04f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2016-08-09 Jason Merrill + 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 * constexpr.c (cxx_eval_constant_expression): Check COMPLETE_TYPE_P before calling is_really_empty_class. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 8249d934229..e21647a642e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1561,20 +1561,20 @@ mark_abi_tags (tree t, bool val) /* 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 - add any missing tags. */ + return any missing tags, and add them to T if JUST_CHECKING is false. */ -static void -check_abi_tags (tree t, tree subob) +static tree +check_abi_tags (tree t, tree subob, bool just_checking = false) { bool inherit = DECL_P (t); if (!inherit && !warn_abi_tag) - return; + return NULL_TREE; tree decl = TYPE_P (t) ? TYPE_NAME (t) : t; if (!TREE_PUBLIC (decl)) /* No need to worry about things local to this TU. */ - return; + return NULL_TREE; 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); - 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)); if (attr) @@ -1597,6 +1605,8 @@ check_abi_tags (tree t, tree subob) } mark_abi_tags (t, false); + + return data.tags; } /* 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 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)) check_abi_tags (decl, TREE_TYPE (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))); } +/* 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 inherit_targ_abi_tags (tree t) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 70a42f87103..f32613c05b7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5686,6 +5686,7 @@ extern void inherit_targ_abi_tags (tree); extern void defaulted_late_check (tree); extern bool defaultable_fn_check (tree); extern void check_abi_tags (tree); +extern tree missing_abi_tags (tree); extern void fixup_type_variants (tree); extern void fixup_attribute_variants (tree); extern tree* decl_cloned_function_p (const_tree, bool); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index b6c96283f4f..f7ff221d941 100644 --- a/gcc/cp/mangle.c +++ b/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) \ (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. */ struct GTY(()) globals { /* 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 int local_class_index (tree); static void maybe_check_abi_tags (tree, tree = NULL_TREE); +static bool equal_abi_tags (tree, tree); /* Control functions. */ @@ -1329,16 +1338,52 @@ write_unqualified_name (tree 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 - 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. */ + 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_CODE (decl) != NAMESPACE_DECL) - write_abi_tags (get_abi_tags (decl)); + { + tree res = DECL_TEMPLATE_RESULT (tmpl); + if (res == NULL_TREE) + /* 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. */ @@ -1381,15 +1426,11 @@ tree_string_cmp (const void *p1, const void *p2) TREE_STRING_POINTER (s2)); } -/* ID is the name of a function or type with abi_tags attribute TAGS. - Write out the name, suitably decorated. */ +/* Return the TREE_LIST of TAGS as a sorted VEC. */ -static void -write_abi_tags (tree tags) +static vec * +sorted_abi_tags (tree tags) { - if (tags == NULL_TREE) - return; - vec * vec = make_tree_vector(); for (tree t = tags; t; t = TREE_CHAIN (t)) @@ -1402,6 +1443,20 @@ write_abi_tags (tree tags) 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 * vec = sorted_abi_tags (tags); + unsigned i; tree str; FOR_EACH_VEC_ELT (*vec, i, str) { @@ -1413,6 +1468,43 @@ write_abi_tags (tree tags) release_tree_vector (vec); } +/* Simplified unique_ptr clone to release a tree vec on exit. */ + +struct releasing_vec +{ + typedef vec 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. ::= li # "" IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */ diff --git a/gcc/testsuite/g++.dg/abi/abi-tag21.C b/gcc/testsuite/g++.dg/abi/abi-tag21.C new file mode 100644 index 00000000000..53599f7f4c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag21.C @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } +// { dg-options -Wabi=10 } + +struct [[gnu::abi_tag ("foo")]] A +{ + template static T f(); + template static A g(); +}; + +template struct B +{ + static decltype(A::f()) fa(decltype(A::f())); + static decltype(A::f()) fv(); // { dg-warning "mangled name" } + static decltype(A::g()) ga(decltype(A::g())); + static decltype(A::g()) gv(); + template + static decltype(A::f()) hv(); +}; + +int main() +{ + B::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } } + B::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvEv" } } + B::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } } + B::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvB3fooEv" } } + B::hv(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } } +} diff --git a/gcc/testsuite/g++.dg/abi/abi-tag21a.C b/gcc/testsuite/g++.dg/abi/abi-tag21a.C new file mode 100644 index 00000000000..3c513336c01 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag21a.C @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fabi-version=10 -Wabi" } + +struct [[gnu::abi_tag ("foo")]] A +{ + template static T f(); + template static A g(); +}; + +template struct B +{ + static decltype(A::f()) fa(decltype(A::f())); + static decltype(A::f()) fv(); // { dg-warning "mangled name" } + static decltype(A::g()) ga(decltype(A::g())); + static decltype(A::g()) gv(); + template + static decltype(A::f()) hv(); +}; + +int main() +{ + B::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } } + B::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvB3fooEv" } } + B::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } } + B::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvB3fooEv" } } + B::hv(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } } +} diff --git a/gcc/testsuite/g++.dg/abi/abi-tag21b.C b/gcc/testsuite/g++.dg/abi/abi-tag21b.C new file mode 100644 index 00000000000..d4090f4843a --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag21b.C @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fabi-version=9 -Wabi" } + +struct [[gnu::abi_tag ("foo")]] A +{ + template static T f(); + template static A g(); +}; + +template struct B +{ + static decltype(A::f()) fa(decltype(A::f())); + static decltype(A::f()) fv(); + static decltype(A::g()) ga(decltype(A::g())); + static decltype(A::g()) gv(); // { dg-warning "mangled name" } + template + static decltype(A::f()) hv(); +}; + +int main() +{ + B::fa(0); // { dg-final { scan-assembler "_ZN1BIiE2faEi" } } + B::fv(); // { dg-final { scan-assembler "_ZN1BIiE2fvEv" } } + B::ga(A()); // { dg-final { scan-assembler "_ZN1BIiE2gaE1AB3foo" } } + B::gv(); // { dg-final { scan-assembler "_ZN1BIiE2gvEv" } } + B::hv(); // { dg-final { scan-assembler "_ZN1BIiE2hvIiEEDTclsr1AB3foo1fIT_EEEv" } } +}