diff mbox

C++ PATCH for c++/44282 (ia32 calling convention attributes and mangling)

Message ID 556D144D.6010404@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 2, 2015, 2:26 a.m. UTC
A recent change broke bootstrap on ia32 because code intended to strip 
non-type-identity attributes from template arguments was also stripping 
type-identity attributes such as the ia32 calling convention attributes. 
   When I fixed that it reminded me of this bug: we weren't mangling the 
function pointer type differently based on the calling convention.  This 
patch fixes that.

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

Patch

commit 0707fcaee20275a8955ab5741df70831c8e9e350
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Apr 25 07:45:02 2015 -0400

    	PR c++/44282
    gcc/cp/
    	* mangle.c (attr_strcmp): New.
    	(write_CV_qualifiers_for_type): Also write out attributes that
    	affect type identity.
    	(write_type): Strip all attributes after writing qualifiers.
    libiberty/
    	* cp-demangle.c (cplus_demangle_type): Handle arguments to vendor
    	extended qualifier.

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index e9eb511..748306b 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -894,7 +894,7 @@  c_common_post_options (const char **pfilename)
   /* Change flag_abi_version to be the actual current ABI level for the
      benefit of c_cpp_builtins.  */
   if (flag_abi_version == 0)
-    flag_abi_version = 8;
+    flag_abi_version = 9;
 
   /* Set C++ standard to C++98 if not specified on the command line.  */
   if (c_dialect_cxx () && cxx_dialect == cxx_unset)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 647ec70..8151179 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -75,6 +75,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-ref.h"
 #include "cgraph.h"
 #include "wide-int.h"
+#include "attribs.h"
 
 /* Debugging support.  */
 
@@ -1916,11 +1917,15 @@  write_type (tree type)
        candidates.  */
     {
       tree t = TYPE_MAIN_VARIANT (type);
+      if (TYPE_ATTRIBUTES (t) && !OVERLOAD_TYPE_P (t))
+	t = cp_build_type_attribute_variant (t, NULL_TREE);
+      gcc_assert (t != type);
       if (TREE_CODE (t) == FUNCTION_TYPE
 	  || TREE_CODE (t) == METHOD_TYPE)
 	{
 	  t = build_ref_qualified_type (t, type_memfn_rqual (type));
-	  if (abi_version_at_least (8))
+	  if (abi_version_at_least (8)
+	      || type == TYPE_MAIN_VARIANT (type))
 	    /* Avoid adding the unqualified function type as a substitution.  */
 	    write_function_type (t);
 	  else
@@ -2168,6 +2173,20 @@  write_type (tree type)
     add_substitution (type);
 }
 
+/* qsort callback for sorting a vector of attribute entries.  */
+
+static int
+attr_strcmp (const void *p1, const void *p2)
+{
+  tree a1 = *(const tree*)p1;
+  tree a2 = *(const tree*)p2;
+
+  const attribute_spec *as1 = lookup_attribute_spec (get_attribute_name (a1));
+  const attribute_spec *as2 = lookup_attribute_spec (get_attribute_name (a2));
+
+  return strcmp (as1->name, as2->name);
+}
+
 /* Non-terminal <CV-qualifiers> for type nodes.  Returns the number of
    CV-qualifiers written for TYPE.
 
@@ -2182,9 +2201,55 @@  write_CV_qualifiers_for_type (const tree type)
 
        "In cases where multiple order-insensitive qualifiers are
        present, they should be ordered 'K' (closest to the base type),
-       'V', 'r', and 'U' (farthest from the base type) ..."
+       'V', 'r', and 'U' (farthest from the base type) ..."  */
 
-     Note that we do not use cp_type_quals below; given "const
+  /* Mangle attributes that affect type identity as extended qualifiers.
+
+     We mangle them onto the obstack, then copy the result into a string
+     vector and back up the obstack.  Once we've handled all of them we
+     sort them and write them out in order.
+
+     We don't do this with classes and enums because their attributes
+     are part of their definitions, not something added on.  */
+
+  if (abi_version_at_least (9) && !OVERLOAD_TYPE_P (type))
+    {
+      auto_vec<tree> vec;
+      for (tree a = TYPE_ATTRIBUTES (type); a; a = TREE_CHAIN (a))
+	{
+	  tree name = get_attribute_name (a);
+	  const attribute_spec *as = lookup_attribute_spec (name);
+	  if (as && as->affects_type_identity
+	      && !is_attribute_p ("abi_tag", name))
+	    vec.safe_push (a);
+	}
+      vec.qsort (attr_strcmp);
+      while (!vec.is_empty())
+	{
+	  tree a = vec.pop();
+	  const attribute_spec *as
+	    = lookup_attribute_spec (get_attribute_name (a));
+
+	  write_char ('U');
+	  write_unsigned_number (strlen (as->name));
+	  write_string (as->name);
+	  if (TREE_VALUE (a))
+	    {
+	      write_char ('I');
+	      for (tree args = TREE_VALUE (a); args;
+		   args = TREE_CHAIN (args))
+		{
+		  tree arg = TREE_VALUE (args);
+		  write_template_arg (arg);
+		}
+	      write_char ('E');
+	    }
+
+	  ++num_qualifiers;
+	}
+    }
+
+  /* Note that we do not use cp_type_quals below; given "const
      int[3]", the "const" is emitted with the "int", not with the
      array.  */
   cp_cv_quals quals = TYPE_QUALS (type);
diff --git a/gcc/testsuite/g++.dg/abi/mangle-regparm.C b/gcc/testsuite/g++.dg/abi/mangle-regparm.C
new file mode 100644
index 0000000..7d4121b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-regparm.C
@@ -0,0 +1,29 @@ 
+// { dg-do run { target i?86-*-* } }
+// { dg-final { scan-assembler "_Z18IndirectExternCallIPU7stdcallU7regparmILi3EEFviiEiEvT_T0_S3_" } }
+
+typedef __SIZE_TYPE__ size_t;
+
+template <typename F, typename T>
+void IndirectExternCall(F f, T t1, T t2) {
+  typedef F (*WrapF)(F);
+  f (t1, t2);
+}
+
+__attribute__((regparm(3), stdcall))
+void regparm_func (int i, int j)
+{
+  if (i != 24 || j != 42)
+    __builtin_abort();
+}
+
+void normal_func (int i, int j)
+{
+  if (i != 24 || j != 42)
+    __builtin_abort();
+}
+
+int main()
+{
+  IndirectExternCall (regparm_func, 24, 42);
+  IndirectExternCall (normal_func, 24, 42);
+}
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 77c2cee..2988b6b 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -2470,6 +2470,9 @@  cplus_demangle_type (struct d_info *di)
     case 'U':
       d_advance (di, 1);
       ret = d_source_name (di);
+      if (d_peek_char (di) == 'I')
+	ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+			   d_template_args (di));
       ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
 			 cplus_demangle_type (di), ret);
       break;
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index a030685..6ea64ae 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4356,3 +4356,6 @@  _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z
 --format=gnu-v3
 _Z1fSsB3fooS_
 f(std::string[abi:foo], std::string[abi:foo])
+--format=gnu-v3
+_Z18IndirectExternCallIPU7stdcallU7regparmILi3EEFviiEiEvT_T0_S3_
+void IndirectExternCall<void ( regparm<3> stdcall*)(int, int), int>(void ( regparm<3> stdcall*)(int, int), int, void ( regparm<3> stdcall*)(int, int))