From: Jan Hubicka Date: Fri, 10 Jan 2014 09:33:24 +0000 (+0100) Subject: re PR c++/58252 (ice in gimple_get_virt_method_for_binfo with -O2) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a3788dde0ed8aea741c59cc6f995ebfcb2374961;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6a18852cd34..b22e4000678 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2014-01-10 Jan Hubicka + + 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 * config/mips/driver-native.c (host_detect_local_cpu): Handle new diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 24b8ebc0353..b0bedacd609 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -614,10 +614,8 @@ maybe_record_node (vec &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 &nodes, tree binfo, tree otr_type, - tree type_binfo, + vec &type_binfos, HOST_WIDE_INT otr_token, tree outer_type, HOST_WIDE_INT offset, @@ -642,10 +640,32 @@ record_target_from_binfo (vec &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 &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 &nodes, { tree binfo = TYPE_BINFO (type->type); unsigned int i; + vec 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 4a9b5637c83..eaf5348c95e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2014-01-10 Jan Hubicka + + 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 * 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 00000000000..aee95147a63 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-20.C @@ -0,0 +1,31 @@ +#include +/* { 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 00000000000..d38a7a7ea4b --- /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 _CORBA_Sequence { + public: typedef _CORBA_Sequence 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 _CORBA_Unbounded_Sequence : public _CORBA_Sequence { + inline _CORBA_Unbounded_Sequence_WChar() { // { dg-warning "forbids declaration" } + } + }; + class _CORBA_ObjRef_Var_base { + }; + template 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 00000000000..cb0ebbe35f9 --- /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(); +}