diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c946683d46e2f6bf99ee44add3a65857409111ed..a347b05182c7a2b46c538774baa6e2ea777e2d3c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +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. + 2010-11-02 Martin Jambor <mjambor@suse.cz> PR tree-optimization/45875 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aa80464b054e2e3a9fd49ae098c63fe456621687..471b009da58309425c82581785c0dc1b05343106 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-11-02 Martin Jambor <mjambor@suse.cz> + + PR middle-end/46120 + * g++.dg/ipa/ivinline-9.C: New test. + 2010-11-02 Martin Jambor <mjambor@suse.cz> PR tree-optimization/45875 diff --git a/gcc/testsuite/g++.dg/ipa/ivinline-9.C b/gcc/testsuite/g++.dg/ipa/ivinline-9.C new file mode 100644 index 0000000000000000000000000000000000000000..429b6f4f00c8dd56066b26d59524993f5c5ec474 --- /dev/null +++ b/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" } } */ diff --git a/gcc/tree.c b/gcc/tree.c index a74603156586de0784fb80ab1a1dca6da940a967..1cc99f07c67a697fcecc3008cf19e1d5d403a3fd 100644 --- a/gcc/tree.c +++ b/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_WIDE_INT offset, tree expected_type) 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. */