re PR c++/13118 ([ABI] Missed covariant return thunk)
authorNathan Sidwell <nathan@codesourcery.com>
Fri, 12 Dec 2003 18:22:23 +0000 (18:22 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Fri, 12 Dec 2003 18:22:23 +0000 (18:22 +0000)
cp:
PR c++/13118
* cp-tree.h (lang_decl_u): Add thunk_alias member.
(THUNK_VIRTUAL_OFFSET): Must be a FUNCTION_DECL.
(THUNK_ALIAS_P): Remove.
(THUNK_ALIAS): Adjust.
* class.c (update_vtable_entry_for_fn): Get the vbase within the
overriding function's return type.
(dump_thunk): Adjust THUNK_ALIAS printing.
(build_vtbl_initializer): Adjust THUNK_ALIAS use.
* method.c (make_thunk): Revert 12881 test change. Clear
THUNK_ALIAS.
(finish_thunk): Adjust THUNK_ALIAS setting.
(use_thunk): Adjust THUNK_ALIAS use.
* semantics.c (emit_associated_thunks): Likewise.
testsuite:
PR c++/13118
* g++.dg/abi/covariant3.C: New.

From-SVN: r74576

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/method.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/covariant3.C [new file with mode: 0644]

index 6b57a9137bc57c32311dd7a45d13ef5f20261622..427a36b165e150746b3744dac18d3704817e0a10 100644 (file)
@@ -1,5 +1,20 @@
 2003-12-12  Nathan Sidwell  <nathan@codesourcery.com>
 
+       PR c++/13118
+       * cp-tree.h (lang_decl_u): Add thunk_alias member.
+       (THUNK_VIRTUAL_OFFSET): Must be a FUNCTION_DECL.
+       (THUNK_ALIAS_P): Remove.
+       (THUNK_ALIAS): Adjust.
+       * class.c (update_vtable_entry_for_fn): Get the vbase within the
+       overriding function's return type.
+       (dump_thunk): Adjust THUNK_ALIAS printing.
+       (build_vtbl_initializer): Adjust THUNK_ALIAS use.
+       * method.c (make_thunk): Revert 12881 test change. Clear
+       THUNK_ALIAS.
+       (finish_thunk): Adjust THUNK_ALIAS setting.
+       (use_thunk): Adjust THUNK_ALIAS use.
+       * semantics.c (emit_associated_thunks): Likewise.
+
        PR c++/13114, c++/13115
        * class.c (layout_empty_base): Propagate the move of an empty base
        to offset zero.
index bc4445241a3668e934f24967649dd84228612ab1..ff615fe2c3b50def100c50170bca24f88863c345 100644 (file)
@@ -2168,13 +2168,22 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
       
       if (DECL_THUNK_P (fn))
        {
+         my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);
          fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
          virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
        }
       else
        fixed_offset = virtual_offset = NULL_TREE;
 
-      if (!virtual_offset)
+      if (virtual_offset)
+       /* Find the equivalent binfo within the return type of the
+          overriding function. We will want the vbase offset from
+          there.  */
+       virtual_offset =
+         TREE_VALUE (purpose_member
+                     (BINFO_TYPE (virtual_offset),
+                      CLASSTYPE_VBASECLASSES (TREE_TYPE (over_return))));
+      else
        {
          /* There was no existing virtual thunk (which takes
             precedence).  */
@@ -6715,11 +6724,7 @@ dump_thunk (FILE *stream, int indent, tree thunk)
           !DECL_THUNK_P (thunk) ? "function"
           : DECL_THIS_THUNK_P (thunk) ? "this-thunk" : "covariant-thunk",
           name ? IDENTIFIER_POINTER (name) : "<unset>");
-  if (!DECL_THUNK_P (thunk))
-    /*NOP*/;
-  else if (THUNK_ALIAS_P (thunk))
-    fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
-  else
+  if (DECL_THUNK_P (thunk))
     {
       HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
       tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
@@ -6734,6 +6739,8 @@ dump_thunk (FILE *stream, int indent, tree thunk)
        fprintf (stream, " vbase=" HOST_WIDE_INT_PRINT_DEC "(%s)",
                 tree_low_cst (BINFO_VPTR_FIELD (virtual_adjust), 0),
                 type_as_string (BINFO_TYPE (virtual_adjust), TFF_SCOPE));
+      if (THUNK_ALIAS (thunk))
+       fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
     }
   fprintf (stream, "\n");
   for (thunks = DECL_THUNKS (thunk); thunks; thunks = TREE_CHAIN (thunks))
@@ -7406,7 +7413,7 @@ build_vtbl_initializer (tree binfo,
        {
          if (!DECL_NAME (fn))
            finish_thunk (fn);
-         if (THUNK_ALIAS_P (fn))
+         if (THUNK_ALIAS (fn))
            {
              fn = THUNK_ALIAS (fn);
              BV_FN (v) = fn;
index 968d0b3ec16a0057064260433e97ac70367594ad..250318e721c5388ea987b68f59e6230f900fd88c 100644 (file)
@@ -1634,12 +1634,17 @@ struct lang_decl_flags GTY(())
   unsigned this_thunk_p : 1;
 
   union lang_decl_u {
-    /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
-       is DECL_TEMPLATE_INFO.  */
+    /* In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
+       VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this is
+       DECL_TEMPLATE_INFO.  */
     tree GTY ((tag ("0"))) template_info;
 
     /* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL.  */
     struct cp_binding_level * GTY ((tag ("1"))) level;
+
+    /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
+       THUNK_ALIAS.  */
+    tree GTY ((tag ("2"))) thunk_alias;
   } GTY ((desc ("%1.u1sel"))) u;
 
   union lang_decl_u2 {
@@ -2859,12 +2864,17 @@ struct lang_decl GTY(())
    for the result pointer adjustment.
 
    The constant adjustment is given by THUNK_FIXED_OFFSET.  If the
-   vcall or vbase offset is required, the index into the vtable is given by
-   THUNK_VIRTUAL_OFFSET.
-
-   Due to ordering constraints in class layout, it is possible to have
-   equivalent covariant thunks. THUNK_ALIAS_P and THUNK_ALIAS are used
-   in those cases.  */
+   vcall or vbase offset is required, THUNK_VIRTUAL_OFFSET is
+   used. For this pointer adjusting thunks, it is the vcall offset
+   into the vtable.  For result pointer adjusting thunks it is the
+   binfo of the virtual base to convert to.  Use that binfo's vbase
+   offset.
+
+   It is possible to have equivalent covariant thunks.  These are
+   distinct virtual covariant thunks whose vbase offsets happen to
+   have the same value.  THUNK_ALIAS is used to pick one as the
+   canonical thunk, which will get all the this pointer adjusting
+   thunks attached to it.  */
 
 /* An integer indicating how many bytes should be subtracted from the
    this or result pointer when this function is called.  */
@@ -2882,15 +2892,11 @@ struct lang_decl GTY(())
    binfos.)  */
 
 #define THUNK_VIRTUAL_OFFSET(DECL) \
-  (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
+  (LANG_DECL_U2_CHECK (FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
 
 /* A thunk which is equivalent to another thunk. */
-#define THUNK_ALIAS_P(DECL) \
-  (THUNK_VIRTUAL_OFFSET (DECL) && DECL_P (THUNK_VIRTUAL_OFFSET (DECL)))
-
-/* When THUNK_ALIAS_P is true, this indicates the thunk which is
-   aliased.  */
-#define THUNK_ALIAS(DECL) THUNK_VIRTUAL_OFFSET (DECL)
+#define THUNK_ALIAS(DECL) \
+  (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.u.thunk_alias)
 
 /* For thunk NODE, this is the FUNCTION_DECL thunked to.  */
 #define THUNK_TARGET(NODE)                             \
index a08ae6bab913bf9394694f7406a2fdd0ce82badc..bd1e2ad9ec5cf8d2e26f5eeb9012579d95ad6616 100644 (file)
@@ -124,51 +124,15 @@ make_thunk (tree function, bool this_adjusting,
      thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
      will be a BINFO.  */
   for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
-    {
-      if (DECL_THIS_THUNK_P (thunk) != this_adjusting
-         || THUNK_FIXED_OFFSET (thunk) != d)
-       /*not me*/;
-      else if (this_adjusting)
-       {
-         if (!virtual_offset)
-           {
-             /* We want a non-virtual covariant thunk.  */
-             if (!THUNK_VIRTUAL_OFFSET (thunk))
-               return thunk;
-           }
-         else if (THUNK_VIRTUAL_OFFSET (thunk))
-           {
-             if (tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
-                                     virtual_offset))
-               return thunk;
-           }
-       }
-      else
-       {
-         if (!virtual_offset)
-           {
-             /* We want a non-virtual covariant thunk.  */
-             if (!THUNK_VIRTUAL_OFFSET (thunk))
-               return thunk;
-           }
-         else if (!THUNK_VIRTUAL_OFFSET (thunk))
-           /*not me*/;
-         else if (THUNK_ALIAS_P (thunk))
-           {
-             /* We have already determined the thunks for FUNCTION,
-                and there is a virtual covariant thunk alias.  We
-                must compare the vbase offsets of the binfo we have
-                been given, and the binfo of the thunk.  */
-             tree binfo = THUNK_VIRTUAL_OFFSET (THUNK_ALIAS (thunk));
-             
-             if (tree_int_cst_equal (BINFO_VPTR_FIELD (virtual_offset),
-                                     BINFO_VPTR_FIELD (binfo)))
-               return THUNK_ALIAS (thunk);
-           }
-         else if (THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)
-           return thunk;
-       }
-    }
+    if (DECL_THIS_THUNK_P (thunk) == this_adjusting
+       && THUNK_FIXED_OFFSET (thunk) == d
+       && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
+       && (!virtual_offset
+           || (this_adjusting
+               ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
+                                     virtual_offset)
+               : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
+      return thunk;
   
   /* All thunks must be created before FUNCTION is actually emitted;
      the ABI requires that all thunks be emitted together with the
@@ -195,6 +159,7 @@ make_thunk (tree function, bool this_adjusting,
   THUNK_TARGET (thunk) = function;
   THUNK_FIXED_OFFSET (thunk) = d;
   THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
+  THUNK_ALIAS (thunk) = NULL_TREE;
   
   /* The thunk itself is not a constructor or destructor, even if
      the thing it is thunking to is.  */
@@ -254,7 +219,7 @@ finish_thunk (tree thunk)
        if (DECL_NAME (cov_probe) == name)
          {
            my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
-           THUNK_ALIAS (thunk) = (THUNK_ALIAS_P (cov_probe)
+           THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
                                   ? THUNK_ALIAS (cov_probe) : cov_probe);
            break;
          }
@@ -376,7 +341,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 
   /* We should never be using an alias, always refer to the
      aliased thunk.  */
-  my_friendly_assert (!THUNK_ALIAS_P (thunk_fndecl), 20031023);
+  my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
 
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
index a5e93a235679e324ba80416dcf54a7029d16707b..8039ca78368c0e6ec08b48a68da75b17f4201b3f 100644 (file)
@@ -2836,7 +2836,7 @@ emit_associated_thunks (tree fn)
       
       for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
        {
-         if (!THUNK_ALIAS_P (thunk))
+         if (!THUNK_ALIAS (thunk))
            {
              use_thunk (thunk, /*emit_p=*/1);
              if (DECL_RESULT_THUNK_P (thunk))
index 62c363e673ac5e1a561d5bd738fbc0086f7fc50d..cabc671b40dc006f74f3a7965d73f3fa8fdb1027 100644 (file)
@@ -1,3 +1,8 @@
+2003-12-12  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/13118
+       * g++.dg/abi/covariant3.C: New.
+
 2003-12-12  Jakub Jelinek  <jakub@redhat.com>
 
        * g++.dg/eh/ia64-1.C: New test.
diff --git a/gcc/testsuite/g++.dg/abi/covariant3.C b/gcc/testsuite/g++.dg/abi/covariant3.C
new file mode 100644 (file)
index 0000000..178157c
--- /dev/null
@@ -0,0 +1,85 @@
+// { dg-do run }
+
+// Copyright (C) 2003 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 12 Dec 2003 <nathan@codesourcery.com>
+// Origin:  grigory@stl.sarov.ru
+
+// PR c++/13118. Missing covariant thunk.
+
+struct c0 {};
+struct c1 : virtual c0 {
+  virtual c0* f6();
+};
+
+struct c5 {
+    virtual void foo();
+};
+
+struct c10 : virtual c1 {
+    virtual void foo();
+};
+
+struct c1a : c1 {}; // disambiguation
+
+struct c11 : virtual c10, c1a {
+  int i;
+  virtual c1* f6 () = 0;
+};
+
+struct c18 : c5, virtual c1 {
+    virtual void bar();
+};
+
+struct c28 : virtual c0, virtual c11 {
+    virtual c18* f6();
+};
+
+c0 *c1::f6 () {}
+void c5::foo () {}
+void c10::foo () {}
+void c18::bar () {}
+
+c18 ret;
+
+c18 *c28::f6 ()
+{
+  return &ret;
+}
+
+bool check_c1 (c1 *ptr)
+{
+  c0 *r = ptr->f6 ();
+  return r != &ret;
+}
+bool check_c10 (c10 *ptr)
+{
+  c0 *r = ptr->f6 ();
+  return r != &ret;
+}
+bool check_c11 (c11 *ptr)
+{
+  c1 *r = ptr->f6 ();
+  return r != &ret;
+}
+bool check_c28 (c28 *ptr)
+{
+  c18 *r = ptr->f6 ();
+  return r != &ret;
+}
+
+int main ()
+{
+  c28 obj;
+  
+  if (check_c1 (static_cast<c1a *> (&obj)))
+    return 1;
+  if (check_c1 (static_cast<c10 *> (&obj)))
+    return 2;
+  if (check_c10 (&obj))
+    return 3;
+  if (check_c11 (&obj))
+    return 4;
+  if (check_c28 (&obj))
+    return 5;
+  return 0;
+}