The first patch corrects a remaining issue with the GCC 6 fix for ABI
tags on template member functions.  We were missing tags on them, and
I fixed that by setting tags on the template, but the proper fix is to
look at the instantiation rather than the template to find the
relevant tags, since the type we mangle is the instantiated type.

The second patch corrects a bug whereby we were mangling tags on a
conversion function twice.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 47a130c94ba180704779c0e024adee84a8f001e5
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jul 29 22:33:04 2016 -0400

        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.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 8249d93..e21647a 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 70a42f8..f32613c 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 b6c9628..f7ff221 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<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))
@@ -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<tree, va_gc> * 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<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.  */
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 0000000..53599f7
--- /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 <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" } }
+}
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 0000000..3c51333
--- /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 <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" } }
+}
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 0000000..d4090f4
--- /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 <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" } }
+}
commit 4de6cc8588ff230fde67fc3a6a7eb10597480613
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jul 29 22:34:01 2016 -0400

        PR c++/71712 - ABI tags on conversion ops.
    
        * class.c (check_abi_tags): Don't duplicate tags for conversion ops.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index e21647a..10286a7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1618,6 +1618,7 @@ check_abi_tags (tree decl)
   if (VAR_P (decl))
     check_abi_tags (decl, TREE_TYPE (decl));
   else if (TREE_CODE (decl) == FUNCTION_DECL
+          && !DECL_CONV_FN_P (decl)
           && !mangle_return_type_p (decl))
     check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)));
 }
@@ -1632,6 +1633,9 @@ 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
+          /* Don't check DECL_CONV_FN_P here like we do in check_abi_tags, so
+             that we can use this function for setting need_abi_warning
+             regardless of the current flag_abi_version.  */
           && !mangle_return_type_p (decl))
     return check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)), true);
   else
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index f7ff221..b42c6f9 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1383,6 +1383,15 @@ write_unqualified_name (tree decl)
     }
 
   tree tags = get_abi_tags (decl);
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CONV_FN_P (decl)
+      && any_abi_below (11))
+    if (tree mtags = missing_abi_tags (decl))
+      {
+       if (abi_warn_or_compat_version_crosses (11))
+         G.need_abi_warning = true;
+       if (!abi_version_at_least (11))
+         tags = chainon (mtags, tags);
+      }
   write_abi_tags (tags);
 }
 
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag22.C 
b/gcc/testsuite/g++.dg/abi/abi-tag22.C
new file mode 100644
index 0000000..e649233
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag22.C
@@ -0,0 +1,11 @@
+// PR c++/71712
+// { dg-options -Wabi=10 }
+
+struct __attribute__((abi_tag("A", "B"))) A { };
+struct A18 {
+  operator A();                        // { dg-warning "mangled name" }
+};
+void f18_test() {
+  // { dg-final { scan-assembler "_ZN3A18cv1AB1AB1BEv" } }
+  A a = A18();
+}
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag22a.C 
b/gcc/testsuite/g++.dg/abi/abi-tag22a.C
new file mode 100644
index 0000000..c27fac6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag22a.C
@@ -0,0 +1,11 @@
+// PR c++/71712
+// { dg-options "-fabi-version=10 -Wabi" }
+
+struct __attribute__((abi_tag("A", "B"))) A { };
+struct A18 {
+  operator A();                        // { dg-warning "mangled name" }
+};
+void f18_test() {
+  // { dg-final { scan-assembler "_ZN3A18cv1AB1AB1BB1AB1BEv" } }
+  A a = A18();
+}

Reply via email to