class.c (modify_vtable_entry): Remove unused variable.
authorNathan Sidwell <nathan@codesourcery.com>
Tue, 31 Dec 2002 19:43:16 +0000 (19:43 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 31 Dec 2002 19:43:16 +0000 (19:43 +0000)
cp:
* class.c (modify_vtable_entry): Remove unused variable.
(get_vcall_index): Always expect a non-thunk.
(update_vtable_entry_for_fn): Combine covariant adjustments, when
overriding a thunk. Pass get_vcall_index a non-thunk.

* decl2.c (finish_file): Mark undefined inlines as extern.
testsuite:
* g++.dg/inherit/covariant8.C: New test.

From-SVN: r60710

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/inherit/covariant8.C [new file with mode: 0644]

index 921c0de..987e42b 100644 (file)
@@ -1,3 +1,12 @@
+2002-12-31  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * class.c (modify_vtable_entry): Remove unused variable.
+       (get_vcall_index): Always expect a non-thunk.
+       (update_vtable_entry_for_fn): Combine covariant adjustments, when
+       overriding a thunk. Pass get_vcall_index a non-thunk.
+
+       * decl2.c (finish_file): Mark undefined inlines as extern.
+
 2002-12-31  Mark Mitchell  <mark@codesourcery.com>
 
        * cp-tree.def (RETURN_INIT): Remove.
index 0ce3f11..b54c1f6 100644 (file)
@@ -716,8 +716,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
   if (fndecl != BV_FN (v)
       || !tree_int_cst_equal (delta, BV_DELTA (v)))
     {
-      tree base_fndecl;
-
       /* We need a new vtable for BINFO.  */
       if (make_new_vtable (t, binfo))
        {
@@ -730,7 +728,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
          v = *virtuals;
        }
 
-      base_fndecl = BV_FN (v);
       BV_DELTA (v) = delta;
       BV_VCALL_INDEX (v) = NULL_TREE;
       BV_FN (v) = fndecl;
@@ -2331,9 +2328,6 @@ get_vcall_index (tree fn, tree type)
 {
   tree v;
 
-  if (DECL_THUNK_P (fn))
-    fn = THUNK_TARGET (fn);
-
   for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
     if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
        || same_signature_p (fn, TREE_PURPOSE (v)))
@@ -2361,18 +2355,18 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
   tree delta;
   tree virtual_base;
   tree first_defn;
+  tree overrider_fn, overrider_target;
+  tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;
+  tree over_return, base_return;
   bool lost = false;
 
-  if (DECL_THUNK_P (fn))
-    fn = THUNK_TARGET (fn);
-  
   /* Find the nearest primary base (possibly binfo itself) which defines
      this function; this is the class the caller will convert to when
      calling FN through BINFO.  */
   for (b = binfo; ; b = get_primary_binfo (b))
     {
       my_friendly_assert (b, 20021227);
-      if (look_for_overrides_here (BINFO_TYPE (b), fn))
+      if (look_for_overrides_here (BINFO_TYPE (b), target_fn))
        break;
 
       /* The nearest definition is from a lost primary.  */
@@ -2382,58 +2376,85 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
   first_defn = b;
 
   /* Find the final overrider.  */
-  overrider = find_final_overrider (TYPE_BINFO (t), b, fn);
+  overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);
   if (overrider == error_mark_node)
     return;
-  {
-    /* Check for adjusting covariant return types. */
-    tree over_return = TREE_TYPE (TREE_TYPE (TREE_PURPOSE (overrider)));
-    tree base_return = TREE_TYPE (TREE_TYPE (fn));
-
-    if (POINTER_TYPE_P (over_return)
-       && TREE_CODE (over_return) == TREE_CODE (base_return)
-       && CLASS_TYPE_P (TREE_TYPE (over_return))
-       && CLASS_TYPE_P (TREE_TYPE (base_return)))
-      {
-       tree binfo;
-       base_kind kind;
+  overrider_target = overrider_fn = TREE_PURPOSE (overrider);
+  
+  /* Check for adjusting covariant return types. */
+  over_return = TREE_TYPE (TREE_TYPE (overrider_target));
+  base_return = TREE_TYPE (TREE_TYPE (target_fn));
+  
+  if (POINTER_TYPE_P (over_return)
+      && TREE_CODE (over_return) == TREE_CODE (base_return)
+      && CLASS_TYPE_P (TREE_TYPE (over_return))
+      && CLASS_TYPE_P (TREE_TYPE (base_return)))
+    {
+      /* If FN is a covariant thunk, we must figure out the adjustment
+         to the final base FN was converting to. As OVERRIDER_TARGET might
+         also be converting to the return type of FN, we have to
+         combine the two conversions here.  */
+      tree fixed_offset, virtual_offset;
+      
+      if (DECL_THUNK_P (fn))
+       {
+         fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
+         virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
+         if (virtual_offset)
+           virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset),
+                                             TREE_TYPE (over_return));
+       }
+      else
+       fixed_offset = virtual_offset = NULL_TREE;
 
-       binfo = lookup_base (TREE_TYPE (over_return), TREE_TYPE (base_return),
-                            ba_check | ba_quiet, &kind);
+      if (!virtual_offset)
+       {
+         /* There was no existing virtual thunk (which takes
+            precidence). */
+         tree thunk_binfo;
+         base_kind kind;
+         
+         thunk_binfo = lookup_base (TREE_TYPE (over_return),
+                                    TREE_TYPE (base_return),
+                                    ba_check | ba_quiet, &kind);
 
-       if (binfo && (kind == bk_via_virtual || !BINFO_OFFSET_ZEROP (binfo)))
-         {
-           tree fixed_offset = BINFO_OFFSET (binfo);
-           tree virtual_offset = NULL_TREE;
-           tree thunk;
-           
-           if (kind == bk_via_virtual)
-             {
-               while (!TREE_VIA_VIRTUAL (binfo))
-                 binfo = BINFO_INHERITANCE_CHAIN (binfo);
-               
-               /* If the covariant type is within the class hierarchy
-                  we are currently laying out, the vbase index is not
-                  yet known, so we have to remember the virtual base
-                  binfo. */
-               virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo),
-                                                 TREE_TYPE (over_return));
-               fixed_offset = size_diffop (fixed_offset,
-                                           BINFO_OFFSET (virtual_offset));
-             }
-           
-           /* Replace the overriding function with a covariant thunk.
-              We will emit the overriding function in its own slot
-              as well. */
-           thunk = make_thunk (TREE_PURPOSE (overrider), /*this_adjusting=*/0,
-                               fixed_offset, virtual_offset);
-           TREE_PURPOSE (overrider) = thunk;
-           if (!virtual_offset && !DECL_NAME (thunk))
-             finish_thunk (thunk);
-         }
-      }
-  }
+         if (thunk_binfo && (kind == bk_via_virtual
+                             || !BINFO_OFFSET_ZEROP (thunk_binfo)))
+           {
+             tree offset = BINFO_OFFSET (thunk_binfo);
 
+             if (kind == bk_via_virtual)
+               {
+                 /* We convert via virtual base. Find the virtual
+                    base and adjust the fixed offset to be from there.  */
+                 while (!TREE_VIA_VIRTUAL (thunk_binfo))
+                   thunk_binfo = BINFO_INHERITANCE_CHAIN (thunk_binfo);
+             
+                 virtual_offset = binfo_for_vbase (BINFO_TYPE (thunk_binfo),
+                                                   TREE_TYPE (over_return));
+                 offset = size_diffop (offset,
+                                       BINFO_OFFSET (virtual_offset));
+               }
+             if (fixed_offset)
+               /* There was an existing fixed offset, this must be
+                  from the base just converted to, and the base the
+                  FN was thunking to.  */
+               fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);
+             else
+               fixed_offset = offset;
+           }
+       }
+      
+      if (fixed_offset || virtual_offset)
+       /* Replace the overriding function with a covariant thunk.  We
+          will emit the overriding function in its own slot as
+          well. */
+       overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/0,
+                                  fixed_offset, virtual_offset);
+    }
+  else
+    my_friendly_assert (!DECL_THUNK_P (fn), 20021231);
+  
   /* Assume that we will produce a thunk that convert all the way to
      the final overrider, and not to an intermediate virtual base.  */
   virtual_base = NULL_TREE;
@@ -2476,16 +2497,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
     delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
                         BINFO_OFFSET (binfo));
 
-  modify_vtable_entry (t, 
-                      binfo, 
-                      TREE_PURPOSE (overrider),
-                      delta,
-                      virtuals);
+  modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
 
   if (virtual_base)
     BV_VCALL_INDEX (*virtuals) 
-      = get_vcall_index (TREE_PURPOSE (overrider),
-                        BINFO_TYPE (virtual_base));
+      = get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));
 }
 
 /* Called from modify_all_vtables via dfs_walk.  */
index 3346a1f..e27c668 100644 (file)
@@ -2977,9 +2977,13 @@ struct lang_decl GTY(())
 /* A tree indicating how to perform the virtual adjustment. For a this
    adjusting thunk it is the number of bytes to be added to the vtable
    to find the vcall offset. For a result adjusting thunk, it is the
-   binfo of the relevant virtual base.  The vptr is always located at
-   offset zero from the this or result pointer.  If NULL, then there
-   is no virtual adjust.  */
+   binfo of the relevant virtual base.  If NULL, then there is no
+   virtual adjust.  (The vptr is always located at offset zero from
+   the this or result pointer.)  (If the covariant type is within the
+   class hierarchy being layed out, the vbase index is not yet known
+   at the point we need to create the thunks, hence the need to use
+   binfos.)  */
+
 #define THUNK_VIRTUAL_OFFSET(DECL) \
   (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
 
index 6efb9bd..8e440e9 100644 (file)
@@ -2802,7 +2802,14 @@ finish_file ()
 
       if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
          && !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)))
-       cp_warning_at ("inline function `%D' used but never defined", decl);
+       {
+         cp_warning_at ("inline function `%D' used but never defined", decl);
+         /* This symbol is effectively an "extern" declaration now.
+            This is not strictly necessary, but removes a duplicate
+            warning.  */
+         TREE_PUBLIC (decl) = 1;
+       }
+      
     }
   
   /* We give C linkage to static constructors and destructors.  */
index f3378e4..b63e008 100644 (file)
@@ -1,3 +1,7 @@
+2002-12-31  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/inherit/covariant8.C: New test.
+
 2002-12-31  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/init/array9.C: New test.
diff --git a/gcc/testsuite/g++.dg/inherit/covariant8.C b/gcc/testsuite/g++.dg/inherit/covariant8.C
new file mode 100644 (file)
index 0000000..33dc431
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile }
+
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 31 Dec 2002 <nathan@codesourcery.com>
+
+// ICE with covariant thunks.
+
+struct c0 {};
+
+struct c1 : virtual c0
+{
+  virtual c0 &f2 ();
+};
+
+struct c2 
+{
+  int m;
+};
+
+struct c3 : virtual c0, virtual c1, c2
+{
+  virtual c1 &f2 ();
+};
+
+c1 &c3::f2 ()
+{
+  throw 0;
+}
+
+struct c4 : virtual c3, virtual c0, virtual c1 {};
+
+struct c8 : virtual c2, virtual c0 {};
+
+struct c12 : virtual c4, virtual c3, virtual c8 {};