C++ PATCH for c++/9381 (stdcall/regparm attributes on pointers to member functions)

View: New views
1 Messages — Rating Filter:   Alert me  

C++ PATCH for c++/9381 (stdcall/regparm attributes on pointers to member functions)

by Jason Merrill :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The bug in PR 9381 was that we were discarding attributes when we
convert FUNCTION_TYPE to METHOD_TYPE.  For good measure, I went through
and checked every place that creates a METHOD_TYPE to make sure that we
preserve attributes as appropriate.

Tested x86_64-pc-linux-gnu, applied to trunk.  I plan to apply a subset
of this patch to the 4.3 and 4.4 branches after testing.

[9381.patch]

commit 6755990549adba887d6bec82c2f44c8e0dbfeb7f
Author: Jason Merrill <jason@...>
Date:   Fri Nov 6 00:05:39 2009 -0500

    PR c++/9381
    * decl2.c (build_memfn_type): Preserve attributes.
    (cp_reconstruct_complex_type): Likewise.
    (maybe_retrofit_in_chrg): Likewise.
    * call.c (standard_conversion): Use build_memfn_type.
    * pt.c (tsubst): Likewise.
    * decl.c (build_ptrmem_type): Likewise
    (check_function_type): Preserve attributes.
    * tree.c (cp_build_type_attribute_variant): Propagate exception
    specs on METHOD_TYPE, too.
    (strip_typedefs): Preserve exception specs and attributes.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0979f3a..1aebaac 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -896,10 +896,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
   || cp_type_quals (fbase) != cp_type_quals (tbase))
  return NULL;
 
-      from = cp_build_qualified_type (tbase, cp_type_quals (fbase));
-      from = build_method_type_directly (from,
- TREE_TYPE (fromfn),
- TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
+      from = build_memfn_type (fromfn, tbase, cp_type_quals (tbase));
       from = build_ptrmemfunc_type (build_pointer_type (from));
       conv = build_conv (ck_pmem, from, conv);
       conv->base_p = true;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 4020144..c798ba2 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4104,6 +4104,7 @@ adjust_clone_args (tree decl)
       /* A default parameter has been added. Adjust the
  clone's parameters.  */
       tree exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
+      tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (clone));
       tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
       tree type;
 
@@ -4121,6 +4122,8 @@ adjust_clone_args (tree decl)
  clone_parms);
       if (exceptions)
  type = build_exception_variant (type, exceptions);
+      if (attrs)
+ type = cp_build_type_attribute_variant (type, attrs);
       TREE_TYPE (clone) = type;
 
       clone_parms = NULL_TREE;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 97f1ac1..5e2f85f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7170,16 +7170,9 @@ build_ptrmem_type (tree class_type, tree member_type)
 {
   if (TREE_CODE (member_type) == METHOD_TYPE)
     {
-      tree arg_types;
-
-      arg_types = TYPE_ARG_TYPES (member_type);
-      class_type = (cp_build_qualified_type
-    (class_type,
-     cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types)))));
-      member_type
- = build_method_type_directly (class_type,
-      TREE_TYPE (member_type),
-      TREE_CHAIN (arg_types));
+      tree arg_types = TYPE_ARG_TYPES (member_type);
+      cp_cv_quals quals = cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types)));
+      member_type = build_memfn_type (member_type, class_type, quals);
       return build_ptrmemfunc_type (build_pointer_type (member_type));
     }
   else
@@ -11551,7 +11544,7 @@ lookup_enumerator (tree enumtype, tree name)
 }
 
 
-/* We're defining DECL.  Make sure that it's type is OK.  */
+/* We're defining DECL.  Make sure that its type is OK.  */
 
 static void
 check_function_type (tree decl, tree current_function_parms)
@@ -11585,9 +11578,12 @@ check_function_type (tree decl, tree current_function_parms)
      TREE_CHAIN (args));
       else
  fntype = build_function_type (void_type_node, args);
-      TREE_TYPE (decl)
+      fntype
  = build_exception_variant (fntype,
    TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)));
+      fntype = (cp_build_type_attribute_variant
+ (fntype, TYPE_ATTRIBUTES (TREE_TYPE (decl))));
+      TREE_TYPE (decl) = fntype;
     }
   else
     abstract_virtuals_error (decl, TREE_TYPE (fntype));
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index dbb9fb4..53f66ad 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -114,20 +114,27 @@ tree
 build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals)
 {
   tree raises;
+  tree attrs;
   int type_quals;
 
   if (fntype == error_mark_node || ctype == error_mark_node)
     return error_mark_node;
 
+  gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
+      || TREE_CODE (fntype) == METHOD_TYPE);
+
   type_quals = quals & ~TYPE_QUAL_RESTRICT;
   ctype = cp_build_qualified_type (ctype, type_quals);
+  raises = TYPE_RAISES_EXCEPTIONS (fntype);
+  attrs = TYPE_ATTRIBUTES (fntype);
   fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
        (TREE_CODE (fntype) == METHOD_TYPE
  ? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
  : TYPE_ARG_TYPES (fntype)));
-  raises = TYPE_RAISES_EXCEPTIONS (fntype);
   if (raises)
     fntype = build_exception_variant (fntype, raises);
+  if (attrs)
+    fntype = cp_build_type_attribute_variant (fntype, attrs);
 
   return fntype;
 }
@@ -237,6 +244,9 @@ maybe_retrofit_in_chrg (tree fn)
   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
     fntype = build_exception_variant (fntype,
       TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)));
+  if (TYPE_ATTRIBUTES (TREE_TYPE (fn)))
+    fntype = (cp_build_type_attribute_variant
+      (fntype, TYPE_ATTRIBUTES (TREE_TYPE (fn))));
   TREE_TYPE (fn) = fntype;
 
   /* Now we've got the in-charge parameter.  */
@@ -1219,6 +1229,8 @@ cp_reconstruct_complex_type (tree type, tree bottom)
   else
     return bottom;
 
+  if (TYPE_ATTRIBUTES (type))
+    outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type));
   return cp_build_qualified_type (outer, TYPE_QUALS (type));
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 75180ea..dd453c5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10015,13 +10015,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   {
     /* The type of the implicit object parameter gets its
        cv-qualifiers from the FUNCTION_TYPE. */
-    tree method_type;
-    tree this_type = cp_build_qualified_type (TYPE_MAIN_VARIANT (r),
-      cp_type_quals (type));
     tree memptr;
-    method_type = build_method_type_directly (this_type,
-      TREE_TYPE (type),
-      TYPE_ARG_TYPES (type));
+    tree method_type = build_memfn_type (type, r, cp_type_quals (type));
     memptr = build_ptrmemfunc_type (build_pointer_type (method_type));
     return cp_build_qualified_type_real (memptr, cp_type_quals (t),
  complain);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index b79093a..5aea55e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1050,6 +1050,10 @@ strip_typedefs (tree t)
  else
     result = build_function_type (type,
   arg_types);
+
+ if (TYPE_RAISES_EXCEPTIONS (t))
+  result = build_exception_variant (result,
+    TYPE_RAISES_EXCEPTIONS (t));
       }
       break;
     default:
@@ -1058,6 +1062,8 @@ strip_typedefs (tree t)
 
   if (!result)
       result = TYPE_MAIN_VARIANT (t);
+  if (TYPE_ATTRIBUTES (t))
+    result = cp_build_type_attribute_variant (result, TYPE_ATTRIBUTES (t));
   return cp_build_qualified_type (result, cp_type_quals (t));
 }
 
@@ -2609,7 +2615,8 @@ cp_build_type_attribute_variant (tree type, tree attributes)
   tree new_type;
 
   new_type = build_type_attribute_variant (type, attributes);
-  if (TREE_CODE (new_type) == FUNCTION_TYPE
+  if ((TREE_CODE (new_type) == FUNCTION_TYPE
+       || TREE_CODE (new_type) == METHOD_TYPE)
       && (TYPE_RAISES_EXCEPTIONS (new_type)
   != TYPE_RAISES_EXCEPTIONS (type)))
     new_type = build_exception_variant (new_type,
diff --git a/gcc/testsuite/g++.dg/abi/regparm1.C b/gcc/testsuite/g++.dg/abi/regparm1.C
new file mode 100644
index 0000000..a83c477
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/regparm1.C
@@ -0,0 +1,40 @@
+// PR c++/29911 (9381)
+// { dg-options -std=c++0x }
+// { dg-do run { target i?86-*-* x86_64-*-* } }
+
+extern "C" int printf(const char *, ...);
+
+void *save_this;
+int *save_addr1, *save_addr2;
+
+struct Base
+{
+  __attribute((regparm(3))) void
+  set(int *addr1, int *addr2)
+  {
+    if (this != save_this)
+      printf("error! this == %p, should be %p\n", this, save_this);
+    if (addr1 != save_addr1)
+      printf("error! addr1 == %p, should be %p\n", addr1, save_addr1);
+    if (addr2 != save_addr2)
+      printf("error! addr2 == %p, should be %p\n", addr2, save_addr1);
+  }
+};
+
+int main()
+{
+  void (__attribute((regparm(3))) Base::* pfm)(int *, int *) = &Base::set;
+  __typeof (&Base::set) pfm2 = &Base::set;
+  decltype (&Base::set) pfm3 = &Base::set;
+  auto pfm4 = &Base::set;
+
+  Base obj; save_this = &obj;
+  int x, y; save_addr1 = &x; save_addr2 = &y;
+
+  (obj.* pfm) (&x, &y);
+  (obj.* pfm2) (&x, &y);
+  (obj.* pfm3) (&x, &y);
+  (obj.* pfm4) (&x, &y);
+
+  return 0;
+}