aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-01-10 10:33:24 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2014-01-10 09:33:24 +0000
commita3788dde0ed8aea741c59cc6f995ebfcb2374961 (patch)
treec00d40de8dff450430f5f9dc1048fecc0b0bc1f7 /gcc
parent6606b43e46accbdf72916ed106e16c1569c2765a (diff)
downloadgcc-a3788dde0ed8aea741c59cc6f995ebfcb2374961.zip
gcc-a3788dde0ed8aea741c59cc6f995ebfcb2374961.tar.gz
gcc-a3788dde0ed8aea741c59cc6f995ebfcb2374961.tar.bz2
re PR c++/58252 (ice in gimple_get_virt_method_for_binfo with -O2)
PR ipa/58252 PR ipa/59226 * ipa-devirt.c record_target_from_binfo): Take as argument stack of binfos and lookup matching one for virtual inheritance. (possible_polymorphic_call_targets_1): Update. * g++.dg/ipa/devirt-20.C: New testcase. * g++.dg/torture/pr58252.C: Likewise. * g++.dg/torture/pr59226.C: Likewise. From-SVN: r206516
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/ipa-devirt.c43
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-20.C31
-rw-r--r--gcc/testsuite/g++.dg/torture/pr58252.C142
-rw-r--r--gcc/testsuite/g++.dg/torture/pr59226.C27
6 files changed, 248 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6a18852..b22e400 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2014-01-10 Jan Hubicka <hubicka@ucw.cz>
+
+ PR ipa/58252
+ PR ipa/59226
+ * ipa-devirt.c record_target_from_binfo): Take as argument
+ stack of binfos and lookup matching one for virtual inheritance.
+ (possible_polymorphic_call_targets_1): Update.
+
2014-01-10 Huacai Chen <chenhc@lemote.com>
* config/mips/driver-native.c (host_detect_local_cpu): Handle new
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 24b8ebc..b0bedac 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -614,10 +614,8 @@ maybe_record_node (vec <cgraph_node *> &nodes,
This match what get_binfo_at_offset does, but with offset
being unknown.
- TYPE_BINFO is binfo holding an virtual table matching
- BINFO's type. In the case of single inheritance, this
- is binfo of BINFO's type ancestor (vtable is shared),
- otherwise it is binfo of BINFO's type.
+ TYPE_BINFOS is a stack of BINFOS of types with defined
+ virtual table seen on way from class type to BINFO.
MATCHED_VTABLES tracks virtual tables we already did lookup
for virtual function in. INSERTED tracks nodes we already
@@ -630,7 +628,7 @@ static void
record_target_from_binfo (vec <cgraph_node *> &nodes,
tree binfo,
tree otr_type,
- tree type_binfo,
+ vec <tree> &type_binfos,
HOST_WIDE_INT otr_token,
tree outer_type,
HOST_WIDE_INT offset,
@@ -642,10 +640,32 @@ record_target_from_binfo (vec <cgraph_node *> &nodes,
int i;
tree base_binfo;
- gcc_checking_assert (BINFO_VTABLE (type_binfo));
+ if (BINFO_VTABLE (binfo))
+ type_binfos.safe_push (binfo);
if (types_same_for_odr (type, outer_type))
{
+ int i;
+ tree type_binfo = NULL;
+
+ /* Lookup BINFO with virtual table. For normal types it is always last
+ binfo on stack. */
+ for (i = type_binfos.length () - 1; i >= 0; i--)
+ if (BINFO_OFFSET (type_binfos[i]) == BINFO_OFFSET (binfo))
+ {
+ type_binfo = type_binfos[i];
+ break;
+ }
+ if (BINFO_VTABLE (binfo))
+ type_binfos.pop ();
+ /* If this is duplicated BINFO for base shared by virtual inheritance,
+ we may not have its associated vtable. This is not a problem, since
+ we will walk it on the other path. */
+ if (!type_binfo)
+ {
+ gcc_assert (BINFO_VIRTUAL_P (binfo));
+ return;
+ }
tree inner_binfo = get_binfo_at_offset (type_binfo,
offset, otr_type);
/* For types in anonymous namespace first check if the respective vtable
@@ -676,12 +696,11 @@ record_target_from_binfo (vec <cgraph_node *> &nodes,
/* Walking bases that have no virtual method is pointless excercise. */
if (polymorphic_type_binfo_p (base_binfo))
record_target_from_binfo (nodes, base_binfo, otr_type,
- /* In the case of single inheritance,
- the virtual table is shared with
- the outer type. */
- BINFO_VTABLE (base_binfo) ? base_binfo : type_binfo,
+ type_binfos,
otr_token, outer_type, offset, inserted,
matched_vtables, anonymous);
+ if (BINFO_VTABLE (binfo))
+ type_binfos.pop ();
}
/* Lookup virtual methods matching OTR_TYPE (with OFFSET and OTR_TOKEN)
@@ -701,11 +720,13 @@ possible_polymorphic_call_targets_1 (vec <cgraph_node *> &nodes,
{
tree binfo = TYPE_BINFO (type->type);
unsigned int i;
+ vec <tree> type_binfos = vNULL;
- record_target_from_binfo (nodes, binfo, otr_type, binfo, otr_token,
+ record_target_from_binfo (nodes, binfo, otr_type, type_binfos, otr_token,
outer_type, offset,
inserted, matched_vtables,
type->anonymous_namespace);
+ type_binfos.release ();
for (i = 0; i < type->derived_types.length (); i++)
possible_polymorphic_call_targets_1 (nodes, inserted,
matched_vtables,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4a9b563..eaf5348 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2014-01-10 Jan Hubicka <hubicka@ucw.cz>
+
+ PR ipa/58252
+ PR ipa/59226
+ * g++.dg/ipa/devirt-20.C: New testcase.
+ * g++.dg/torture/pr58252.C: Likewise.
+ * g++.dg/torture/pr59226.C: Likewise.
+
2014-01-10 Max Ostapenko <m.ostapenko@partner.samsung.com>
* c-c++-common/asan/no-asan-stack.c: New test.
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-20.C b/gcc/testsuite/g++.dg/ipa/devirt-20.C
new file mode 100644
index 0000000..aee9514
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-20.C
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-release_ssa" } */
+namespace {
+struct A
+{ int a; virtual int foo() {return a;} void bar() {a=7;} };
+struct B
+{ int b; virtual int foo2() {return b;} void bar2() {b=9;} };
+struct C : public virtual A, public virtual B { };
+struct D : public virtual B, public virtual A { };
+struct E : public C, public D { void bar2() {b=9;} }; }
+int
+main(void)
+{
+ struct E e;
+ struct C *c = &e;
+ struct D *d = &e;
+ struct A *a = &e;
+ struct B *b = &e;
+ e.bar();
+ e.bar2();
+ if (e.foo() + e.foo2() != 16)
+ abort ();
+ if (c->foo() + d->foo2() != 16)
+ abort ();
+ if (a->foo() + b->foo2() != 16)
+ abort ();
+ return 0;
+}
+/* { dg-final { scan-tree-dump-not "abort" "release_ssa" } } */
+/* { dg-final { cleanup-ipa-dump "release_ssa" } } */
diff --git a/gcc/testsuite/g++.dg/torture/pr58252.C b/gcc/testsuite/g++.dg/torture/pr58252.C
new file mode 100644
index 0000000..d38a7a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr58252.C
@@ -0,0 +1,142 @@
+// { dg-do compile }
+// { dg-options "-fpermissive" }
+typedef long unsigned int size_t;
+ typedef bool _CORBA_Boolean;
+ typedef unsigned int _CORBA_ULong;
+ template <class T> class _CORBA_Sequence {
+ public: typedef _CORBA_Sequence<T> T_seq;
+ inline T_seq &operator= (const T_seq &s) {
+ for (unsigned long i=0;
+ i < pd_len;
+ i++) {
+ }
+ }
+ _CORBA_ULong pd_len;
+ };
+ template <class T> class _CORBA_Unbounded_Sequence : public _CORBA_Sequence<T> {
+ inline _CORBA_Unbounded_Sequence_WChar() { // { dg-warning "forbids declaration" }
+ }
+ };
+ class _CORBA_ObjRef_Var_base {
+ };
+ template <class T, class T_Helper> class _CORBA_ObjRef_Var : public _CORBA_ObjRef_Var_base {
+ public: typedef T* ptr_t;
+ typedef T* T_ptr;
+ inline _CORBA_ObjRef_Var() : pd_objref(T_Helper::_nil()) {
+ }
+ inline _CORBA_ObjRef_Var(T_ptr p) : pd_objref(p) {
+ }
+ private: T_ptr pd_objref;
+ };
+ class omniLocalIdentity;
+ class omniObjRef {
+ };
+ class omniServant {
+ public: virtual ~omniServant();
+ virtual void* _ptrToInterface(const char* repoId);
+ };
+ namespace CORBA {
+ class NVList {
+ };
+ class Object {
+ };
+ struct StructMember {
+ };
+ class StructMemberSeq : public _CORBA_Unbounded_Sequence< StructMember > {
+ };
+ class _objref_IRObject : public virtual ::CORBA::Object, public virtual omniObjRef {
+ };
+ class _impl_IRObject : public virtual omniServant {
+ };
+ class _objref_Container;
+ typedef _objref_Container* Container_ptr;
+ class _impl_Contained : public virtual _impl_IRObject {
+ };
+ class _objref_ExceptionDef;
+ typedef _objref_ExceptionDef* ExceptionDef_ptr;
+ class ExceptionDef_Helper {
+ public: typedef ExceptionDef_ptr _ptr_type;
+ static _ptr_type _nil();
+ };
+ typedef _CORBA_ObjRef_Var<_objref_ExceptionDef, ExceptionDef_Helper> ExceptionDef_var;
+ class Container {
+ public: typedef Container_ptr _ptr_type;
+ static const char* _PD_repoId;
+ };
+ class _objref_Container : public virtual _objref_IRObject {
+ ExceptionDef_ptr create_exception(const char* id, const char* name, const char* version, const ::CORBA::StructMemberSeq& members);
+ };
+ class _impl_Container : public virtual _impl_IRObject {
+ public: virtual ~_impl_Container();
+ virtual ExceptionDef_ptr create_exception(const char* id, const char* name, const char* version, const ::CORBA::StructMemberSeq& members) = 0;
+ };
+ class _impl_IDLType : public virtual _impl_IRObject {
+ };
+ class _impl_TypedefDef : public virtual _impl_Contained, public virtual _impl_IDLType {
+ };
+ class _impl_StructDef : public virtual _impl_TypedefDef, public virtual _impl_Container {
+ };
+ }
+ namespace PortableServer {
+ class ServantBase : public virtual omniServant {
+ };
+ }
+ namespace POA_CORBA {
+ class IRObject : public virtual CORBA::_impl_IRObject, public virtual ::PortableServer::ServantBase {
+ };
+ class Contained : public virtual CORBA::_impl_Contained, public virtual IRObject {
+ };
+ class Container : public virtual CORBA::_impl_Container, public virtual IRObject {
+ };
+ class IDLType : public virtual CORBA::_impl_IDLType, public virtual IRObject {
+ };
+ class TypedefDef : public virtual CORBA::_impl_TypedefDef, public virtual Contained, public virtual IDLType {
+ };
+ class StructDef : public virtual CORBA::_impl_StructDef, public virtual TypedefDef, public virtual Container {
+ public: virtual ~StructDef();
+ };
+ }
+ namespace omni {
+ class omniOrbPOA;
+ class giopAddress;
+ }
+ class omniCallDescriptor {
+ public: typedef void (*LocalCallFn)(omniCallDescriptor*, omniServant*);
+ inline omniCallDescriptor(LocalCallFn lcfn, const char* op_, int op_len_, _CORBA_Boolean oneway, const char*const* user_excns_, int n_user_excns_, _CORBA_Boolean is_upcall_) : pd_localCall(lcfn), pd_op(op_), pd_oplen(op_len_), pd_user_excns(user_excns_), pd_n_user_excns(n_user_excns_), pd_is_oneway(oneway), pd_is_upcall(is_upcall_), pd_contains_values(0), pd_first_address_used(0), pd_current_address(0), pd_objref(0), pd_poa(0), pd_localId(0), pd_deadline_secs(0), pd_deadline_nanosecs(0) {
+ }
+ private: LocalCallFn pd_localCall;
+ const char* pd_op;
+ size_t pd_oplen;
+ const char*const* pd_user_excns;
+ int pd_n_user_excns;
+ _CORBA_Boolean pd_is_oneway;
+ _CORBA_Boolean pd_is_upcall;
+ _CORBA_Boolean pd_contains_values;
+ const omni::giopAddress* pd_first_address_used;
+ const omni::giopAddress* pd_current_address;
+ omniObjRef* pd_objref;
+ omni::omniOrbPOA* pd_poa;
+ omniLocalIdentity* pd_localId;
+ unsigned long pd_deadline_secs;
+ unsigned long pd_deadline_nanosecs;
+ };
+ class _0RL_cd_7963219a43724a61_f2000000 : public omniCallDescriptor {
+ public: inline _0RL_cd_7963219a43724a61_f2000000(LocalCallFn lcfn,const char* op_,size_t oplen,_CORBA_Boolean upcall=0): omniCallDescriptor(lcfn, op_, oplen, 0, _user_exns, 0, upcall) {
+ }
+ static const char* const _user_exns[];
+ const char* arg_0;
+ const char* arg_1;
+ const char* arg_2;
+ const CORBA::StructMemberSeq* arg_3;
+ CORBA::ExceptionDef_var result;
+ };
+ static void _0RL_lcfn_7963219a43724a61_03000000(omniCallDescriptor* cd, omniServant* svnt) {
+ _0RL_cd_7963219a43724a61_f2000000* tcd = (_0RL_cd_7963219a43724a61_f2000000*)cd;
+ CORBA::_impl_Container* impl = (CORBA::_impl_Container*) svnt->_ptrToInterface(CORBA::Container::_PD_repoId);
+ tcd->result = impl->create_exception(tcd->arg_0, tcd->arg_1, tcd->arg_2, *tcd->arg_3);
+ }
+ CORBA::ExceptionDef_ptr CORBA::_objref_Container::create_exception(const char* id, const char* name, const char* version, const ::CORBA::StructMemberSeq& members) {
+ _0RL_cd_7963219a43724a61_f2000000 _call_desc(_0RL_lcfn_7963219a43724a61_03000000, "create_exception", 17);
+ }
+ POA_CORBA::StructDef::~StructDef() {
+ }
diff --git a/gcc/testsuite/g++.dg/torture/pr59226.C b/gcc/testsuite/g++.dg/torture/pr59226.C
new file mode 100644
index 0000000..cb0ebbe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr59226.C
@@ -0,0 +1,27 @@
+// { dg-do compile }
+struct A
+{
+ virtual void foo() {}
+};
+
+struct B
+{
+ virtual void foo() {}
+};
+
+struct C : virtual A {};
+
+struct D : virtual A, B
+{
+ virtual void foo() {}
+};
+
+struct E : C, D
+{
+ virtual void foo() {}
+};
+
+void bar(A* p)
+{
+ p->foo();
+}