For the following testcase with three similar functions we do different tree optimizations:
#include <new> struct Foo { Foo() { i[0] = 1; } int i[2]; }; int foo_char(void) { int i[2]; new (reinterpret_cast<char *>(i)) Foo(); return reinterpret_cast<Foo *>(i)->i[0]; } int foo_void(void) { int i[2]; new (reinterpret_cast<void *>(i)) Foo(); return reinterpret_cast<Foo *>(i)->i[0]; } int foo_void_offset(void) { int i[2]; new (reinterpret_cast<void *>(&i[0])) Foo(); return reinterpret_cast<Foo *>(&i[0])->i[0]; } We only can optimize the foo_void_offset() variant to return 1, the foo_void() variant results in <bb 0>: this = (struct Foo *) &i[0]; this->i[0] = 1; i.6 = (struct Foo *) &i; return i.6->i[0]; where the difference starts in what the frontend produces: (void) (TARGET_EXPR <D.1791, (struct Foo *) operator new (8, (void *) &i[0])>; and return <retval> = ((struct Foo *) &i[0])->i[0]; vs. (void) (TARGET_EXPR <D.1783, (struct Foo *) operator new (8, (void *) (int *) &i)>; and return <retval> = ((struct Foo *) (int *) &i)->i[0]; note that mixing &i[0] and i does not allow folding. For the char* variant we even cannot prove that &i is non-null (!?): <bb 0>: i.2 = (char *) &i; __p = i.2; this = (struct Foo *) __p; if (__p != 0B) goto <L1>; else goto <L3>; <L1>:; this->i[0] = 1; <L3>:; i.4 = (struct Foo *) &i; return i.4->i[0]; though this might be somehow related to type-based aliasing rules(?). Note that the char variant does not care if &i[0] or plain i is specified. -- Summary: Missed constant propagation with placement new Product: gcc Version: 4.0.0 Status: UNCONFIRMED Severity: normal Priority: P2 Component: tree-optimization AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: rguenth at tat dot physik dot uni-tuebingen dot de CC: gcc-bugs at gcc dot gnu dot org http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19637