https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58483
--- Comment #23 from Jan Hubicka <hubicka at gcc dot gnu.org> --- one in comment #0 optimizes with me provided that destructors are inline jh@shroud:/tmp> cat tt.C #include <vector> #include <numeric> #include <array> //static int calc(const std::array<int,3> p_ints, const int& p_init) static int calc(const std::vector<int> p_ints, const int& p_init) { return std::accumulate(p_ints.begin(), p_ints.end(), p_init); } int main2() { const int result = calc({10,20,30},100); return result; } jh@shroud:/tmp> ~/trunk-install-new5/bin/g++ -O2 tt.C -S -fdump-tree-all jh@shroud:/tmp> cat tt.C*optimized ;; Function main2 (_Z5main2v, funcdef_no=1316, decl_uid=26734, cgraph_uid=154, symbol_order=174) int main2 () { <bb 2> [local count: 118111600]: return 160; } One in comment #17 does optimize too jh@shroud:/tmp> cat >qq.C int f(void) { int tt = 100; int t[3] = {10,20,30}; int *t1 = new int[3]; __builtin_memcpy(t1, t, sizeof(t)); for(int *i = t1; i != &t1[3]; i++) tt += *i; delete[] t1; return tt; } jh@shroud:/tmp> ~/trunk-install-new5/bin/g++ -O2 qq.C -S -fdump-tree-all jh@shroud:/tmp> cat qq.C*optimized ;; Function f (_Z1fv, funcdef_no=0, decl_uid=2828, cgraph_uid=1, symbol_order=0) int f () { <bb 2> [local count: 268435458]: return 160; } However if I do not rename main to main2 I get in #0 testcase: int main () { void * D.27965; int * __result; static const int C.0[3] = {10, 20, 30}; struct vector D.26783; int * _36; void * _45; <bb 2> [local count: 118111600]: MEM[(struct _Vector_impl_data *)&D.26783] ={v} {CLOBBER(bob)}; MEM <vector(2) long unsigned int> [(int * *)&D.26783] = { 0, 0 }; MEM[(struct _Vector_impl_data *)&D.26783]._M_end_of_storage = 0B; _36 = operator new (12); <bb 3> [local count: 118111600]: __builtin_memcpy (_36, &C.0, 12); __result_29 = _36 + 12; D.26783.D.26624._M_impl.D.25935._M_finish = __result_29; D.26783.D.26624._M_impl.D.25935._M_start = _36; D.26783.D.26624._M_impl.D.25935._M_end_of_storage = __result_29; std::_Vector_base<int, std::allocator<int> >::~_Vector_base (&D.26783.D.26624); D.26783 ={v} {CLOBBER(eob)}; D.26783 ={v} {CLOBBER(eos)}; return 160; <bb 4> [count: 0]: <L6>: std::_Vector_base<int, std::allocator<int> >::~_Vector_base (&D.26783.D.26624); _45 = __builtin_eh_pointer (11); __builtin_unwind_resume (_45); } I think this is kind of important limitation because uninlined destructors in EH are very frequent. Reason why we do not optimize is that the destructor computes size of array being destroyed: void std::_Vector_base<int, std::allocator<int> >::~_Vector_base (struct _Vector_base * const this) { int * _1; int * _2; long int _3; long unsigned int _11; <bb 2> [local count: 1073741824]: _2 = this_7(D)->_M_impl.D.25935._M_start; if (_2 != 0B) goto <bb 3>; [53.47%] else goto <bb 4>; [46.53%] <bb 3> [local count: 574129752]: _1 = this_7(D)->_M_impl.D.25935._M_end_of_storage; _3 = _1 - _2; _11 = (long unsigned int) _3; operator delete (_2, _11); [tail call] <bb 4> [local count: 1073741824]: *this_7(D) ={v} {CLOBBER(eob)}; return; } and that is considered as too big when optimizing for size. delete has a variant without size known. I wonder if for vectors it is not better to use this variant, given that computing size involves some pointer arithmetics. I think I will need to extend ipa-modref to recognize wrappers of removable allocations and deallocations. Here we can figure out that the destructors only reads from block being deleted and then calls particular variant of delete.