https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80331
--- Comment #12 from Jan Hubicka <hubicka at gcc dot gnu.org> --- I think with my patch to basic_string we should have at least arrived to something comparable with clang. With -O2 it is optimized away, with -O2 -D_GLIBCXX_USE_CXX11_ABI=0 I get: int sain () { struct allocator_type D.37493; struct allocator D.33221; struct _Rep * _18; _Atomic_word * _29; char __libc_single_threaded.11_30; unsigned int _33; int _34; <bb 2> [local count: 1073741824]: _18 = std::basic_string<char>::_Rep::_S_create (1, 0, &D.33221); MEM[(char_type &)_18 + 24] = 97; if (_18 != &_S_empty_rep_storage) goto <bb 3>; [10.00%] else goto <bb 8>; [90.00%] <bb 3> [local count: 107374184]: _18->D.33079._M_refcount = 0; _18->D.33079._M_length = 1; MEM[(char_type &)_18 + 25] = 0; D.33221 ={v} {CLOBBER(eos)}; __libc_single_threaded.11_30 = __libc_single_threaded; if (__libc_single_threaded.11_30 != 0) goto <bb 4>; [67.00%] else goto <bb 5>; [33.00%] <bb 4> [local count: 71940704]: MEM[(_Atomic_word *)_18 + 16B] = -1; goto <bb 6>; [100.00%] <bb 5> [local count: 35433481]: _29 = &_18->D.33079._M_refcount; _33 = __atomic_fetch_add_4 (_29, 4294967295, 4); _34 = (int) _33; if (_34 <= 0) goto <bb 6>; [7.88%] else goto <bb 7>; [92.12%] <bb 6> [local count: 27380417]: std::basic_string<char>::_Rep::_M_destroy (_18, &D.37493); <bb 7> [local count: 1073741824]: D.37493 ={v} {CLOBBER(eos)}; return 0; <bb 8> [local count: 966367640]: D.33221 ={v} {CLOBBER(eos)}; goto <bb 7>; [100.00%] } this is not optimized since _M_create and M_destroy are not inlined. Those seems to be invisible to compiler, so even if modref was extended to propagate removable allocations inter-proceduraly, we have problem. With longer string also both clang and GCC will not optimize the code completely. We get: int sain () { size_type __dnew; const struct string s; char * _7; long unsigned int _9; long unsigned int _10; char * _17; long unsigned int __dnew.1_18; long unsigned int __dnew.2_20; char * _21; char * _22; <bb 2> [local count: 1073741824]: MEM[(struct basic_string *)&s] ={v} {CLOBBER(bob)}; MEM[(struct _Alloc_hider *)&s] ={v} {CLOBBER(bob)}; MEM[(struct _Alloc_hider *)&s]._M_p = &s.D.25525._M_local_buf; __dnew = 40; _17 = std::__cxx11::basic_string<char>::_M_create (&s, &__dnew, 0); s._M_dataplus._M_p = _17; __dnew.1_18 = __dnew; s.D.25525._M_allocated_capacity = __dnew.1_18; __builtin_memcpy (_17, "this string is longer than 15 characters", 40); __dnew.2_20 = __dnew; _21 = s._M_dataplus._M_p; _22 = _21 + __dnew.2_20; MEM[(char_type &)_22] = 0; __dnew ={v} {CLOBBER(eos)}; _7 = s._M_dataplus._M_p; if (&s.D.25525._M_local_buf == _7) goto <bb 4>; [18.09%] else goto <bb 3>; [81.91%] <bb 3> [local count: 879501928]: _9 = s.D.25525._M_allocated_capacity; _10 = _9 + 1; operator delete (_7, _10); <bb 4> [local count: 1073741824]: s ={v} {CLOBBER(eob)}; s ={v} {CLOBBER(eos)}; return 0; } Call to _M_create is problem here. Again it is not seen by modref. With -std=c++23 we optimize out the code, while clang doesn't