namespace std { typedef __SIZE_TYPE__ size_t; } inline void* operator new(std::size_t, void* __p) throw() { return __p; } extern "C" void abort (void); class Foo { public: virtual void test (void) { abort (); } }; class Bar { public: virtual void test (void) { } }; int main() { Foo f; Bar *b; b = new (&f) Bar(); b->test(); return 0; }
It is caused by revision 161655: http://gcc.gnu.org/ml/gcc-cvs/2010-07/msg00006.html
Of course it is ;) Before pointer-conversions became useless we didn't propagate the invariant address into the OBJ_TYPE_REF expression. We still have useful function-pointer conversions as well, because dropping them would wreck CALL_EXPRs, too (we need to preserve the original function type, similar to the alias-type on MEM_REFs). I suppose we could do the same for OBJ_TYPE_REFs that I plan(ned) for CALL_EXPRs - store the pointed-to type via a MEM_REF - thus a dereferenced address. You'd then have CALL_EXPR (MEM [fnptr], args ...) OBJ_TYPE_REF (MEM [fnptr], MEM [objptr], index) where both TREE_TYPE of the function and the object are kept like the FE specified them.
The following is miscompiled since ever (and also ICC miscompiles it), so I'm not sure if it is valid to use 'f' to refer to the Bar object. namespace std { typedef __SIZE_TYPE__ size_t; } inline void* operator new(std::size_t, void* __p) throw() { return __p; } extern "C" void abort (void); class Foo { public: virtual void test (void) { abort (); } }; class Bar : public Foo { public: virtual void test (void) { } }; int main() { Foo f; new (&f) Bar(); f.test(); return 0; } A variant with using a pointer of type Bar * like int main() { Foo f; static_cast<Foo *>(new (&f) Bar())->test(); return 0; } only breaks on recent trunk. int main() { Foo f; new (&f) Bar(); (&f)->test(); return 0; } also breaks always. While int main() { Foo f, *p; p = new (&f) Bar(); p->test(); return 0; } works. int main() { Foo f, *p; new (&f) Bar(); ((Foo *)(void *)&f)->test(); return 0; } also works. Fun.
Not a bug; all these testcases (should) have undefined behavior. I'm working on clarifying the standard to that end. This is related to http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#1116 and on the C side, http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_236.htm http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1409.htm
GCC 4.6.0 is being released, adjusting target milestone.
Suspending until the DR is resolved. We didn't get to it in time for C++0x, but the committee seemed to agree that these should be undefined.
*** Bug 93153 has been marked as a duplicate of this bug. ***
The C++ defect has been resolved now: http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1116 So closing as invalid as the behavior was decided as undefined.
DR 1116 is said to be resolved by P0137R1[1]. By looking through it, I don't see how it covers testcases from this pr where "right" pointer is used (like the example in comment 0). And it even introduces std::launder for using "wrong" pointers. Even better, the C++ standard contains a whole paragraph ([basic.life]p9 -- see [2]) describing finer details of killing non-dynamic variables. And the example there features exactly placement new over a local variable: ---------------------------------------------------------------------- class T { }; struct B { ~B(); }; void h() { B b; new (&b) T; } // undefined behavior at block exit ---------------------------------------------------------------------- The examples in this pr don't have classes with non-trivial destructors so they don't hit such UB. [1] http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0137r1.html [2] https://eel.is/c++draft/basic.life#9