public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCHes for abi_tag bugs
@ 2016-01-31 11:49 Jason Merrill
  2016-02-19  6:24 ` Jason Merrill
  0 siblings, 1 reply; 3+ messages in thread
From: Jason Merrill @ 2016-01-31 11:49 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 437 bytes --]

These patches fix a couple of abi_tag bugs that were reported to me 
recently.

The first is an issue whereby all instantiations of a class template 
were sharing tags, so instantiating a template with a tagged type 
argument would apply the tag to another instantiation.  Oops.

The second is an issue where the multiple-initialization guard for a 
tagged variable was not itself tagged.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: tag-share.patch --]
[-- Type: text/x-patch, Size: 1242 bytes --]

commit ca11e70947cc2a94cc8ac2d07733f1f01904bba0
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 29 17:33:24 2016 +0100

    	* pt.c (lookup_template_class_1): Don't share TYPE_ATTRIBUTES
    	between template and instantiation.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 186a5d2..0d0e664 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8482,11 +8482,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	      tree attributes
 		= lookup_attribute (tags[ix], TYPE_ATTRIBUTES (template_type));
 
-	      if (!attributes)
-		;
-	      else if (!TREE_CHAIN (attributes) && !TYPE_ATTRIBUTES (t))
-		TYPE_ATTRIBUTES (t) = attributes;
-	      else
+	      if (attributes)
 		TYPE_ATTRIBUTES (t)
 		  = tree_cons (TREE_PURPOSE (attributes),
 			       TREE_VALUE (attributes),
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag17.C b/gcc/testsuite/g++.dg/abi/abi-tag17.C
new file mode 100644
index 0000000..cb7dbab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag17.C
@@ -0,0 +1,9 @@
+// { dg-final { scan-assembler "_Z3fi1B6_X_tagv" } }
+
+struct __attribute((abi_tag("_A1_tag"))) A1 {};
+template <class T> struct __attribute((abi_tag("_X_tag"))) X {};
+X<int> fi1();
+int main() {
+  X<A1> xa;
+  fi1();
+}

[-- Attachment #3: tag-guard.patch --]
[-- Type: text/x-patch, Size: 3594 bytes --]

commit 615067ce890764a32a1fc6978ec17b6c1a2f4645
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 29 03:02:31 2016 -0500

    	* mangle.c (maybe_check_abi_tags): New.
    	(write_guarded_var_name): Call it.
    	(mangle_ref_init_variable): Call check_abi_tags.

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 4f1eea6..2bb7048 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3931,6 +3931,30 @@ mangle_conv_op_name_for_type (const tree type)
   return identifier;
 }
 
+/* Handle ABI backwards compatibility for past bugs where we didn't call
+   check_abi_tags in places where it's needed: call check_abi_tags and warn if
+   it makes a difference.  */
+
+static void
+maybe_check_abi_tags (tree t)
+{
+  tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
+  tree oldtags = NULL_TREE;
+  if (attr)
+    oldtags = TREE_VALUE (attr);
+
+  check_abi_tags (t);
+
+  if (!attr)
+    attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
+  if (attr && TREE_VALUE (attr) != oldtags
+      && abi_version_crosses (10))
+    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",
+		t, flag_abi_version, warn_abi_version);
+}
+
 /* Write out the appropriate string for this variable when generating
    another mangled name based on this one.  */
 
@@ -3943,7 +3967,15 @@ write_guarded_var_name (const tree variable)
        to the reference, not the temporary.  */
     write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
   else
-    write_name (variable, /*ignore_local_scope=*/0);
+    {
+      /* Before ABI v10 we were failing to call check_abi_tags here.  So if
+	 we're in pre-10 mode, wait until after write_name to call it.  */
+      if (abi_version_at_least (10))
+	maybe_check_abi_tags (variable);
+      write_name (variable, /*ignore_local_scope=*/0);
+      if (!abi_version_at_least (10))
+	maybe_check_abi_tags (variable);
+    }
 }
 
 /* Return an identifier for the name of an initialization guard
@@ -4007,6 +4039,7 @@ mangle_ref_init_variable (const tree variable)
 {
   start_mangling (variable);
   write_string ("_ZGR");
+  check_abi_tags (variable);
   write_name (variable, /*ignore_local_scope=*/0);
   /* Avoid name clashes with aggregate initialization of multiple
      references at once.  */
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag16.C b/gcc/testsuite/g++.dg/abi/abi-tag16.C
new file mode 100644
index 0000000..d4fa142
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag16.C
@@ -0,0 +1,19 @@
+// { dg-options -Wabi=9 }
+// { dg-final { scan-assembler "_ZGVZN1N1FEvE4NameB5cxx11" } }
+namespace std {
+  __extension__ inline namespace __cxx11 __attribute__((abi_tag("cxx11"))) {
+    struct String {
+      String();
+    };
+  }
+}
+namespace N {
+  inline void F() {
+    {
+      static std::String Name;	// { dg-warning "mangled name" }
+    }
+  }
+  void F2() {
+    F();
+  }
+}
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag16a.C b/gcc/testsuite/g++.dg/abi/abi-tag16a.C
new file mode 100644
index 0000000..b02e856
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag16a.C
@@ -0,0 +1,19 @@
+// { dg-options "-fabi-version=9 -Wabi" }
+// { dg-final { scan-assembler "_ZGVZN1N1FEvE4Name" } }
+namespace std {
+  __extension__ inline namespace __cxx11 __attribute__((abi_tag("cxx11"))) {
+    struct String {
+      String();
+    };
+  }
+}
+namespace N {
+  inline void F() {
+    {
+      static std::String Name;	// { dg-warning "mangled name" }
+    }
+  }
+  void F2() {
+    F();
+  }
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: C++ PATCHes for abi_tag bugs
  2016-01-31 11:49 C++ PATCHes for abi_tag bugs Jason Merrill
@ 2016-02-19  6:24 ` Jason Merrill
  0 siblings, 0 replies; 3+ messages in thread
From: Jason Merrill @ 2016-02-19  6:24 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 302 bytes --]

On 01/31/2016 06:49 AM, Jason Merrill wrote:
> These patches fix a couple of abi_tag bugs that were reported to me
> recently.
>
...
>
> The second is an issue where the multiple-initialization guard for a
> tagged variable was not itself tagged.

That didn't completely fix the issue.  Trying again:


[-- Attachment #2: abi-tag.patch --]
[-- Type: text/x-patch, Size: 6147 bytes --]

commit 09ebcab51e037bc236bb804ca5cc5d27a2f1fb9b
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 19 00:51:35 2016 -0500

    	* mangle.c (maybe_check_abi_tags): Add for_decl parm.  Call
    	mangle_decl.
    	(mangle_decl): Call maybe_check_abi_tags for function scope.
    	(mangle_guard_variable): Call maybe_check_abi_tags here.
    	(write_guarded_var_name): Not here.

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 410c7f4..5d38373 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -223,6 +223,7 @@ static void write_local_name (tree, const tree, const tree);
 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);
 
 /* Control functions.  */
 
@@ -3599,6 +3600,9 @@ mangle_decl (const tree decl)
     {
       gcc_assert (TREE_CODE (decl) != TYPE_DECL
 		  || !no_linkage_check (TREE_TYPE (decl), true));
+      if (abi_version_at_least (10))
+	if (tree fn = decl_function_context (decl))
+	  maybe_check_abi_tags (fn, decl);
       id = get_mangled_id (decl);
     }
   SET_DECL_ASSEMBLER_NAME (decl, id);
@@ -3937,26 +3941,39 @@ mangle_conv_op_name_for_type (const tree type)
 
 /* Handle ABI backwards compatibility for past bugs where we didn't call
    check_abi_tags in places where it's needed: call check_abi_tags and warn if
-   it makes a difference.  */
+   it makes a difference.  If FOR_DECL is non-null, it's the declaration
+   that we're actually trying to mangle; if it's null, we're mangling the
+   guard variable for T.  */
 
 static void
-maybe_check_abi_tags (tree t)
+maybe_check_abi_tags (tree t, tree for_decl)
 {
+  if (DECL_ASSEMBLER_NAME_SET_P (t))
+    return;
+
   tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
   tree oldtags = NULL_TREE;
   if (attr)
     oldtags = TREE_VALUE (attr);
 
-  check_abi_tags (t);
+  mangle_decl (t);
 
   if (!attr)
     attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
   if (attr && TREE_VALUE (attr) != oldtags
       && abi_version_crosses (10))
-    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",
-		t, flag_abi_version, warn_abi_version);
+    {
+      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",
+		    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",
+		    t, flag_abi_version, warn_abi_version);
+    }
 }
 
 /* Write out the appropriate string for this variable when generating
@@ -3971,15 +3988,7 @@ write_guarded_var_name (const tree variable)
        to the reference, not the temporary.  */
     write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
   else
-    {
-      /* Before ABI v10 we were failing to call check_abi_tags here.  So if
-	 we're in pre-10 mode, wait until after write_name to call it.  */
-      if (abi_version_at_least (10))
-	maybe_check_abi_tags (variable);
-      write_name (variable, /*ignore_local_scope=*/0);
-      if (!abi_version_at_least (10))
-	maybe_check_abi_tags (variable);
-    }
+    write_name (variable, /*ignore_local_scope=*/0);
 }
 
 /* Return an identifier for the name of an initialization guard
@@ -3988,6 +3997,8 @@ write_guarded_var_name (const tree variable)
 tree
 mangle_guard_variable (const tree variable)
 {
+  if (abi_version_at_least (10))
+    maybe_check_abi_tags (variable);
   start_mangling (variable);
   write_string ("_ZGV");
   write_guarded_var_name (variable);
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag16a.C b/gcc/testsuite/g++.dg/abi/abi-tag16a.C
index b02e856..12fe312 100644
--- a/gcc/testsuite/g++.dg/abi/abi-tag16a.C
+++ b/gcc/testsuite/g++.dg/abi/abi-tag16a.C
@@ -1,4 +1,4 @@
-// { dg-options "-fabi-version=9 -Wabi" }
+// { dg-options "-fabi-version=9" }
 // { dg-final { scan-assembler "_ZGVZN1N1FEvE4Name" } }
 namespace std {
   __extension__ inline namespace __cxx11 __attribute__((abi_tag("cxx11"))) {
@@ -10,7 +10,7 @@ namespace std {
 namespace N {
   inline void F() {
     {
-      static std::String Name;	// { dg-warning "mangled name" }
+      static std::String Name;
     }
   }
   void F2() {
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag18.C b/gcc/testsuite/g++.dg/abi/abi-tag18.C
new file mode 100644
index 0000000..89ee737
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag18.C
@@ -0,0 +1,20 @@
+// { dg-options -Wabi=9 }
+// { dg-final { scan-assembler "_Z1fB7__test1v" } }
+// { dg-final { scan-assembler "_ZZ1fB7__test1vEN1T1gB7__test2Ev" } }
+// { dg-final { scan-assembler "_ZZZ1fB7__test1vEN1T1gB7__test2EvE1x" } }
+// { dg-final { scan-assembler "_ZGVZZ1fB7__test1vEN1T1gB7__test2EvE1x" } }
+
+struct X { ~X(); };
+inline namespace __test1 __attribute__((abi_tag)) { struct A1 { }; }
+inline namespace __test2 __attribute__((abi_tag)) { struct A2 { }; }
+inline A1 f() {
+  struct T {
+    A2 g() {			// { dg-warning "mangled name" }
+      static X x;		// { dg-warning "mangled name" }
+    }
+  };
+  T().g();
+}
+int main() {
+  f();
+}
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag18a.C b/gcc/testsuite/g++.dg/abi/abi-tag18a.C
new file mode 100644
index 0000000..f65f629
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/abi-tag18a.C
@@ -0,0 +1,20 @@
+// { dg-options -fabi-version=9 }
+// { dg-final { scan-assembler "_Z1fB7__test1v" } }
+// { dg-final { scan-assembler "_ZZ1fB7__test1vEN1T1gB7__test2Ev" } }
+// { dg-final { scan-assembler "_ZZZ1fB7__test1vEN1T1gEvE1x" } }
+// { dg-final { scan-assembler "_ZGVZZ1fvEN1T1gEvE1x" } }
+
+struct X { ~X(); };
+inline namespace __test1 __attribute__((abi_tag)) { struct A1 { }; }
+inline namespace __test2 __attribute__((abi_tag)) { struct A2 { }; }
+inline A1 f() {
+  struct T {
+    A2 g() {
+      static X x;
+    }
+  };
+  T().g();
+}
+int main() {
+  f();
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* C++ PATCHes for abi_tag bugs
@ 2016-08-09 16:54 Jason Merrill
  0 siblings, 0 replies; 3+ messages in thread
From: Jason Merrill @ 2016-08-09 16:54 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 483 bytes --]

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.

[-- Attachment #2: abi-tag-mem.diff --]
[-- Type: text/plain, Size: 12693 bytes --]

commit 47a130c94ba180704779c0e024adee84a8f001e5
Author: Jason Merrill <jason@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" } }
+}

[-- Attachment #3: 71712.diff --]
[-- Type: text/plain, Size: 2687 bytes --]

commit 4de6cc8588ff230fde67fc3a6a7eb10597480613
Author: Jason Merrill <jason@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();
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-08-09 16:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-31 11:49 C++ PATCHes for abi_tag bugs Jason Merrill
2016-02-19  6:24 ` Jason Merrill
2016-08-09 16:54 Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).