https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110137
--- Comment #30 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I had further look and I must say I really don't know what if anything is clang++'s -fassume-sane-operator-new vs. -fno-assume-sane-operator-new option doing. Initially when that option has been added the option added implicitly malloc attribute to the replaceable global operator new/new[]. The current trunk adds noalias attribute, whatever that is, instead. Now, we already do have malloc attribute on all the replaceable global operator news, and obviously that is not it. I've tried following testcase with clang++ trunk with both -fassume-sane-operator-new and -fno-assume-sane-operator-new and it emits the same assembly. Plus gcc trunk. In all 3 cases, foo calls mylloc (so it isn't DCEd), but optimizes it to return 0 (so malloc attribute implies non-aliasing). bar is not optimized by any compiler. baz is optimized in all 3 cases to just return 0, so malloc call is DCEd and non-aliasing is implied. qux is fully optimized in all 3 cases (j = 2; store DSEd and k = i; optimized into k = 1;). corge is like foo, non-aliasing implied (returns 0), the call is kept. garply is not optimized at all in all 3 cases. freddy is optimized into just return 0 like baz in all 3 cases. And the only difference between the 2 compilers is in the last function, clang optimizes in waldo k = i; into k = 1; but doesn't DSE j = 2; store, while gcc doesn't optimize either. void *mylloc (__SIZE_TYPE__) __attribute__((malloc)); int i, j, k; int foo (void) { char a; return mylloc (42) == &a; } void * bar (void) { i = 1; j = 2; void *p = mylloc (32); j = 3; k = i; return p; } int baz (void) { char a; return __builtin_malloc (42) == &a; } void * qux (void) { i = 1; j = 2; void *p = __builtin_malloc (32); j = 3; k = i; return p; } int corge (void) { char a; return ::operator new (42) == &a; } void * garply (void) { i = 1; j = 2; void *p = ::operator new (32); j = 3; k = i; return p; } int fredy (void) { char a; return __builtin_operator_new (42) == &a; } void * waldo (void) { i = 1; j = 2; void *p = __builtin_operator_new (32); j = 3; k = i; return p; } So, I think we shouldn't implement -fassume-sane-operator-new because it isn't really useful option. If we want some global flag which says that replaceable global ::operator new/new[]/delete/delete[] doesn't use or modify global state visible to the callers, I think it should be a differently named option. And I wonder what makes clang++ believe that replaceable global operator new can't modify global state visible to the compiler when called from within new expression (or __builtin_operator_new, both work the same). Sure, the C++ standard says that one can omit the calls or replace them with stack allocations or merge them, so relying on particular side-effects is complicated. On the other side, when one actually overrides the replaceable global operator new and implements it with something non-trivial in the current compilation unit, then it certainly will modify the global state etc. Thus, shall we follow clang++ and add the implication that gimple_call_from_new_or_delete which is DECL_IS_REPLACEABLE_OPERATOR_NEW_P (or just DECL_IS_REPLACEABLE_OPERATOR?) implies no modification of global state (and do it without actually giving users a way to stop assuming that)? Or add a new switch which implies it globally regardless of gimple_call_from_new_or_delete? And if the latter, what would be the default?