* 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
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
* constexpr.c (cxx_eval_constant_expression): Check
COMPLETE_TYPE_P before calling is_really_empty_class.
/* 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);
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)
}
mark_abi_tags (t, false);
+
+ return data.tags;
}
/* Check that DECL has all the ABI tags that are used in parts of its type
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
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)
{
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);
#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
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. */
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. */
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<tree, va_gc> *
+sorted_abi_tags (tree tags)
{
- if (tags == NULL_TREE)
- return;
-
vec<tree, va_gc> * vec = make_tree_vector();
for (tree t = tags; t; t = TREE_CHAIN (t))
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;
FOR_EACH_VEC_ELT (*vec, i, str)
{
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.
::= li <source-name> # "" <source-name>
IDENTIFIER is an LITERAL_IDENTIFIER_NODE. */
--- /dev/null
+// { 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" } }
+}
--- /dev/null
+// { 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" } }
+}
--- /dev/null
+// { 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" } }
+}