https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89579
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org, | |law at gcc dot gnu.org, | |redi at gcc dot gnu.org --- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> --- This is caused by the uninitialized __capacity variable in basic_string& operator=(basic_string&& __str); The code is like: // Just move the allocated pointer, our allocator can free it. pointer __data = nullptr; size_type __capacity; if (!_M_is_local()) { if (_Alloc_traits::_S_always_equal()) { // __str can reuse our existing storage. __data = _M_data(); __capacity = _M_allocated_capacity; } else // __str can't use it, so free it. _M_destroy(_M_allocated_capacity); } _M_data(__str._M_data()); _M_length(__str.length()); _M_capacity(__str._M_allocated_capacity); if (__data) { __str._M_data(__data); __str._M_capacity(__capacity); } else __str._M_data(__str._M_local_buf); Although __capacity is never actually used uninitialized (and e.g. the uninit warning pass figures that out), because it is used only if __data is non-NULL and __data is non-NULL only if __capacity is also initialized, with -Og or e.g. with -O1 -fno-tree-dominator-opts, if we don't perform jump threading, we end up with something like: if (&dummy.D.19123._M_local_buf != _35) goto <bb 14>; [70.00%] else goto <bb 15>; [30.00%] <bb 14> [local count: 173485181]: __capacity_44 = dummy.D.19123._M_allocated_capacity; <bb 15> [local count: 247835973]: # __data_47 = PHI <_35(14), 0B(13)> # __capacity_48 = PHI <__capacity_44(14), __capacity_50(D)(13)> dummy._M_dataplus._M_p = _37; _45 = D.24766._M_string_length; dummy._M_string_length = _45; _46 = D.24766.D.19123._M_allocated_capacity; dummy.D.19123._M_allocated_capacity = _46; if (__data_47 != 0B) goto <bb 16>; [70.00%] else goto <bb 17>; [30.00%] <bb 16> [local count: 173485181]: D.24766._M_dataplus._M_p = __data_47; D.24766.D.19123._M_allocated_capacity = __capacity_48; goto <bb 18>; [100.00%] before expansion and later when IRA checks for the clobbered vars, it does: if (VAR_P (decl) && DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)) && regno_clobbered_at_setjmp (setjmp_crosses, REGNO (DECL_RTL (decl)))) where the last one uses: return ((REG_N_SETS (regno) > 1 || REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)), regno)) && REGNO_REG_SET_P (setjmp_crosses, regno)); While REG_N_SETS is just 1 here for the pseudo used for __capacity, because of the uninitialized use in the PHI it is considered live on the entry block and that is why the warning is emitted. Changing libstdc++ code to size_type __capacity = 0; makes the warning away, though we'd need to check if it doesn't result in worse generated code.