summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/gimple-fold.c2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/pr52939.C58
4 files changed, 70 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e3a691e6dc5..e04d1be979c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2012-04-13 Martin Jambor <mjambor@suse.cz>
+
+ PR middle-end/52939
+ * gimple-fold.c (gimple_get_virt_method_for_binfo): Bail out if
+ fold_ctor_reference returns a zero constant.
+
2012-04-13 Enkovich Ilya <ilya.enkovich@intel.com>
* config.gcc: Add i386/gnu-user-common.h before all
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 0ea5d56543f..049da5782af 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -3087,7 +3087,7 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
offset += token * size;
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v),
offset, size);
- if (!fn)
+ if (!fn || integer_zerop (fn))
return NULL_TREE;
gcc_assert (TREE_CODE (fn) == ADDR_EXPR
|| TREE_CODE (fn) == FDESC_EXPR);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b39e623f89f..556d2f6db86 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2012-04-13 Martin Jambor <mjambor@suse.cz>
+
+ PR middle-end/52939
+ * g++.dg/ipa/pr52939.C: New test.
+
2012-04-13 Tom de Vries <tom@codesourcery.com>
* gcc.dg/pr52734.c: New test.
diff --git a/gcc/testsuite/g++.dg/ipa/pr52939.C b/gcc/testsuite/g++.dg/ipa/pr52939.C
new file mode 100644
index 00000000000..e120827bd1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr52939.C
@@ -0,0 +1,58 @@
+/* Verify that we do not ICE on invalid devirtualizations (which might
+ be OK at run-time because never executed). */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */
+
+extern "C" void abort (void);
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+class B : public A
+{
+public:
+ virtual int foo (int i);
+ virtual int bar (int i);
+};
+
+int A::foo (int i)
+{
+ return i + 1;
+}
+
+int B::foo (int i)
+{
+ return i + 2;
+}
+
+int B::bar (int i)
+{
+ return i + 3;
+}
+
+static int middleman (class A *obj, int i)
+{
+ class B *b = (class B *) obj;
+
+ if (i != 1)
+ return b->bar (i);
+ else
+ return i;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+int main (int argc, char *argv[])
+{
+ class A o;
+ if (middleman (&o, get_input ()) != 1)
+ abort ();
+ return 0;
+}