diff mbox

[PR,46120] Fix get_binfo_at_offset

Message ID 20101102152904.GC3200@virgil.arch.suse.de
State New
Headers show

Commit Message

Martin Jambor Nov. 2, 2010, 3:29 p.m. UTC
On Mon, Nov 01, 2010 at 03:36:06PM -0400, Jason Merrill wrote:
> OK, but please add comments here and in
> gimple_get_relevant_ref_binfo to indicate why you're checking for
> offset 0: because that indicates the primary base, whose vtable
> contents are represented in the binfo for the derived class.

Thanks,  I did that and committed the following as revision 166192.

Martin


2010-11-02  Martin Jambor  <mjambor@suse.cz>

	PR middle-end/46120
	* tree.c (get_binfo_at_offset): Bail out on artificial
	fields. Identify primary bases according to their offsets.

	* testsuite/g++.dg/ipa/ivinline-9.C: New test.

Comments

H.J. Lu Nov. 9, 2010, 12:16 a.m. UTC | #1
On Tue, Nov 2, 2010 at 8:29 AM, Martin Jambor <mjambor@suse.cz> wrote:
> On Mon, Nov 01, 2010 at 03:36:06PM -0400, Jason Merrill wrote:
>> OK, but please add comments here and in
>> gimple_get_relevant_ref_binfo to indicate why you're checking for
>> offset 0: because that indicates the primary base, whose vtable
>> contents are represented in the binfo for the derived class.
>
> Thanks,  I did that and committed the following as revision 166192.
>
> Martin
>
>
> 2010-11-02  Martin Jambor  <mjambor@suse.cz>
>
>        PR middle-end/46120
>        * tree.c (get_binfo_at_offset): Bail out on artificial
>        fields. Identify primary bases according to their offsets.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46383
diff mbox

Patch

Index: icln/gcc/tree.c
===================================================================
--- icln.orig/gcc/tree.c
+++ icln/gcc/tree.c
@@ -10906,16 +10906,17 @@  lhd_gcc_personality (void)
 tree
 get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type)
 {
-  tree type;
+  tree type = TREE_TYPE (binfo);
 
-  type = TREE_TYPE (binfo);
-  while (offset > 0)
+  while (true)
     {
-      tree base_binfo, found_binfo;
       HOST_WIDE_INT pos, size;
       tree fld;
       int i;
 
+      gcc_checking_assert (offset >= 0);
+      if (type == expected_type)
+	  return binfo;
       if (TREE_CODE (type) != RECORD_TYPE)
 	return NULL_TREE;
 
@@ -10929,27 +10930,28 @@  get_binfo_at_offset (tree binfo, HOST_WI
 	  if (pos <= offset && (pos + size) > offset)
 	    break;
 	}
-      if (!fld)
+      if (!fld || !DECL_ARTIFICIAL (fld))
 	return NULL_TREE;
 
-      found_binfo = NULL_TREE;
-      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
-	if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
-	  {
-	    found_binfo = base_binfo;
-	    break;
-	  }
-
-      if (!found_binfo)
-	return NULL_TREE;
+      /* Offset 0 indicates the primary base, whose vtable contents are
+	 represented in the binfo for the derived class.  */
+      if (offset != 0)
+	{
+	  tree base_binfo, found_binfo = NULL_TREE;
+	  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+	    if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
+	      {
+		found_binfo = base_binfo;
+		break;
+	      }
+	  if (!found_binfo)
+	    return NULL_TREE;
+	  binfo = found_binfo;
+	}
 
       type = TREE_TYPE (fld);
-      binfo = found_binfo;
       offset -= pos;
     }
-  if (type != expected_type)
-    return NULL_TREE;
-  return binfo;
 }
 
 /* Returns true if X is a typedef decl.  */
Index: icln/gcc/testsuite/g++.dg/ipa/ivinline-9.C
===================================================================
--- /dev/null
+++ icln/gcc/testsuite/g++.dg/ipa/ivinline-9.C
@@ -0,0 +1,93 @@ 
+/* Verify that simple virtual calls are inlined even without early
+   inlining, even when a typecast to an ancestor is involved along the
+   way and that ancestor itself has an ancestor wich is not the
+   primary base class.  */
+/* { dg-do run } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+
+extern "C" void abort (void);
+
+class Distraction
+{
+public:
+  float f;
+  double d;
+  Distraction ()
+  {
+    f = 8.3;
+    d = 10.2;
+  }
+  virtual float bar (float z);
+};
+
+class A
+{
+public:
+  int data;
+  virtual int foo (int i);
+};
+/*
+class D2
+{
+public:
+  virtual float baz (float z)
+  {
+    abort();
+  }
+};
+*/
+class A2 : public Distraction, public A
+{
+  int i2;
+};
+
+class B : public A2
+{
+public:
+  virtual int foo (int i);
+};
+
+float Distraction::bar (float z)
+{
+  f += z;
+  return f/2;
+}
+
+int A::foo (int i)
+{
+  return i + 1;
+}
+
+int B::foo (int i)
+{
+  return i + 2;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+  return 1;
+}
+
+static int middleman_1 (class A *obj, int i)
+{
+  return obj->foo (i);
+}
+
+static int middleman_2 (class B *obj, int i)
+{
+  return middleman_1 (obj, i);
+}
+
+int main (int argc, char *argv[])
+{
+  class B b;
+  int i;
+
+  for (i = 0; i < get_input (); i++)
+    if (middleman_2 (&b, get_input ()) != 3)
+      abort ();
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main"  "inline"  } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */