Hi, this patch fixes a thinko in possible_placement_new which derives that placement new can not happen before beggining of the memory location of the known type. While analysitng the testcase I found that check_stmt_for_type_change is bit stupid to stop on first construction found. In case the constructor call is not even polymorphic, we won't derive any useful context. It is better to continue the walk and look for polymorphic constructor where we can derive at least the speculative outer type.
Bootstrapped/regtested x86_64-linux, will commit it shortly. The patch should be safe to backport to GCC-5 branch after some time. The second hunk is not really neede for correctness, but I think we could include it in backport, too. Switching to speculative propagation ought not trigger wrong code. PR ipa/67056 * ipa-polymorphic-call.c (possible_placement_new): If cur_offset is negative we don't know the type. (check_stmt_for_type_change): Skip constructors of non-polymorphic types as those won't help devirutalization. * g++.dg/ipa/pr67056.C: New testcase. Index: ipa-polymorphic-call.c =================================================================== --- ipa-polymorphic-call.c (revision 229133) +++ ipa-polymorphic-call.c (working copy) @@ -99,6 +99,8 @@ bool possible_placement_new (tree type, tree expected_type, HOST_WIDE_INT cur_offset) { + if (cur_offset < 0) + return true; return ((TREE_CODE (type) != RECORD_TYPE || !TYPE_BINFO (type) || cur_offset >= POINTER_SIZE @@ -1418,7 +1420,21 @@ check_stmt_for_type_change (ao_ref *ao A && TYPE_SIZE (type) && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && tree_fits_shwi_p (TYPE_SIZE (type)) - && tree_to_shwi (TYPE_SIZE (type)) + offset > tci->offset) + && tree_to_shwi (TYPE_SIZE (type)) + offset > tci->offset + /* Some inlined constructors may look as follows: + _3 = operator new (16); + MEM[(struct &)_3] ={v} {CLOBBER}; + MEM[(struct CompositeClass *)_3]._vptr.CompositeClass + = &MEM[(void *)&_ZTV14CompositeClass + 16B]; + _7 = &MEM[(struct CompositeClass *)_3].object; + EmptyClass::EmptyClass (_7); + + When determining dynamic type of _3 and because we stop at first + dynamic type found, we would stop on EmptyClass::EmptyClass (_7). + In this case the emptyclass is not even polymorphic and we miss + it is contained in an outer type that is polymorphic. */ + + && (tci->offset == offset || contains_polymorphic_type_p (type))) { record_known_type (tci, type, tci->offset - offset); return true; Index: testsuite/g++.dg/ipa/pr67056.C =================================================================== --- testsuite/g++.dg/ipa/pr67056.C (revision 0) +++ testsuite/g++.dg/ipa/pr67056.C (revision 0) @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-std=c++11 -O3 -fdump-ipa-cp" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ +#include <memory> + +class EmptyClass { +public: + EmptyClass(); +}; + +EmptyClass::EmptyClass() { +} + +class CompositeClass { +public: + CompositeClass() {} + virtual ~CompositeClass() {} + EmptyClass object; + bool bool1; + bool bool2; +}; + +bool boolFunc() { + return true; +} + +static bool staticBoolFunc(CompositeClass * ptr) { + std::unique_ptr<CompositeClass> up(ptr); + (void)up; + + return boolFunc(); +} + +int main(int, char **) { + staticBoolFunc(new CompositeClass); + return 0; +} + +/* { dg-final { scan-ipa-dump "Speculative outer type:struct CompositeClass" "cp" } } */