<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/61687>61687</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
             [clang: static analyzer] False positive of clang-analyzer-core.uninitialized.Assign with std::stable_sort
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          cmorty
      </td>
    </tr>
</table>

<pre>
    When running `std::stable_sort` on a container of a class with default ctor and default member initialization, `clang-analyzer-core.uninitialized.Assign` will show that a "value assigned to a field in implicit constructor is garbage or undefined".

## Versions
Tested with clang
* 15.0.7
* 16.0.0
* 17.0.0

## Example

[Godbolt](https://godbolt.org/z/8898r7xac)

Running

`/usr/lib/llvm-17/bin/clang --analyze -Qunused-arguments -Xclang -analyzer-opt-analyze-headers -Xclang -analyzer-checker=core.uninitialized.Assign /work/test.cpp`

on

```c++
#include <algorithm>
#include <string>
#include <vector>

class SimpleClass
{
 public:
 int v {};
   std::string s;

   static std::vector<SimpleClass> sortMe(std::vector<SimpleClass> v);
};

std::vector<SimpleClass> SimpleClass::sortMe(std::vector<SimpleClass> v)
{
 std::stable_sort(v.begin(), v.end(), [](const SimpleClass &lhs, const SimpleClass &rhs) {
      return lhs.v < rhs.v || lhs.s < rhs.s;
 });
   return v;
}
```

will produce:

```
/work/test.cpp:5:7: warning: Assigned value is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
 ^~~~~~~~~~~
/work/test.cpp:5:7: warning: Value assigned to field 'v' in implicit constructor is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
 ^~~~~~~~~~~
```

See Details for the whole trace back.

<details>

```
/work/test.cpp:5:7: warning: Assigned value is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:262:3: note: Calling 'get_temporary_buffer<SimpleClass>'
 std::get_temporary_buffer<value_type>(_M_original_len));
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:104:11: note: Assuming '__len' is <= '__max'
      if (__len > __max)
 ^~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:104:7: note: Taking false branch
      if (__len > __max)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:107:14: note: Assuming '__len' is > 0
      while (__len > 0)
 ^~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:107:7: note: Loop condition is true.  Entering loop body
      while (__len > 0)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:109:35: note: Uninitialized value stored to field 'v'
          _Tp* __tmp = static_cast<_Tp*>(::operator new(__len * sizeof(_Tp),
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:111:8: note: Assuming '__tmp' is not equal to null
          if (__tmp != 0)
 ^~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:111:4: note: Taking true branch
          if (__tmp != 0)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:262:3: note: Returning from 'get_temporary_buffer<SimpleClass>'
 std::get_temporary_buffer<value_type>(_M_original_len));
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:15: note: Field 'first' is non-null
      if (__p.first)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:7: note: Taking true branch
      if (__p.first)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:268:8: note: Calling '__uninitialized_construct_buf<SimpleClass *, __gnu_cxx::__normal_iterator<SimpleClass *, std::vector<SimpleClass>>>'
 std::__uninitialized_construct_buf(__p.first, __p.first + __p.second,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:251:7: note: Calling '__uninitialized_construct_buf_dispatch::__ucr'
 std::__uninitialized_construct_buf_dispatch<
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:8: note: '__first' is not equal to '__last'
          if (__first == __last)
 ^~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:4: note: Taking false branch
          if (__first == __last)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:14: note: Assuming '__cur' is equal to '__last'
              for(; __cur != __last; ++__cur, ++__prev)
 ^~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:8: note: Loop condition is false. Execution continues on line 215
 for(; __cur != __last; ++__cur, ++__prev)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:18: note: Calling 'move<SimpleClass &>'
              *__seed = _GLIBCXX_MOVE(*__prev);
 ^~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/move.h:167:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
 ^~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:18: note: Returning from 'move<SimpleClass &>'
              *__seed = _GLIBCXX_MOVE(*__prev);
 ^~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/move.h:167:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
 ^~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:8: note: Calling implicit move assignment operator for 'SimpleClass'
 *__seed = _GLIBCXX_MOVE(*__prev);
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/work/test.cpp:5:7: note: Assigned value is garbage or undefined
class SimpleClass
 ^~~~~~~~~~~
/work/test.cpp:5:7: warning: Value assigned to field 'v' in implicit constructor is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:15: note: Field 'first' is non-null
      if (__p.first)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:7: note: Taking true branch
      if (__p.first)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:268:8: note: Calling '__uninitialized_construct_buf<SimpleClass *, __gnu_cxx::__normal_iterator<SimpleClass *, std::vector<SimpleClass>>>'
 std::__uninitialized_construct_buf(__p.first, __p.first + __p.second,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:251:7: note: Calling '__uninitialized_construct_buf_dispatch::__ucr'
 std::__uninitialized_construct_buf_dispatch<
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:8: note: '__first' is not equal to '__last'
          if (__first == __last)
 ^~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:4: note: Taking false branch
          if (__first == __last)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:14: note: Assuming '__cur' is not equal to '__last'
              for(; __cur != __last; ++__cur, ++__prev)
 ^~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:8: note: Loop condition is true.  Entering loop body
              for(; __cur != __last; ++__cur, ++__prev)
 ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:213:3: note: Calling '_Construct<SimpleClass, SimpleClass>'
 std::_Construct(std::__addressof(*__cur),
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:119:38: note: Calling implicit move constructor for 'SimpleClass'
 ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/work/test.cpp:5:7: note: Value assigned to field 'v' in implicit constructor is garbage or undefined
class SimpleClass
 ^~~~~~~~~~~
```

</details>

If you switch `v` and `s`, this error will not be shown.

## How to Reproduce

```sh
docker run --rm -it -v `pwd`:/work ubuntu

apt update
apt install -y wget lsb-release software-properties-common gnupg

wget https://apt.llvm.org/llvm.sh
chmod u+x llvm.sh

./llvm.sh 17

clang-17 --analyze -Qunused-arguments -Xclang -analyzer-opt-analyze-headers -Xclang -analyzer-checker=core.uninitialized.Assign /work/test.cpp
```

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWtFvozwS_2vcl1EQMU1IHvqQps13n_StTrff3t6-IQOT4Ftjc7ZJ2n24v_1kAwlpybY5VV8qbVGEYjyA5-fxb2bwMGP4RiLekMktmdxdsdoWSt9kpdL28SpV-ePNvwqUoGspudwAmYbG5iRakGhhLEsFJkZpS6YhKAkMMiUt4xI1qLVrCmYM7LgtIMc1q4WFzCoNTOb7CyWWKWrgklvOBP_BLFeS0KV7VyaY3IyYZOLxB-pRpjQGtdyLYh4svALu_TsuBJhC7cAWzAIDQumWiRqhVTIHq4DBmqPIgUvgZSV4xq0btLG69iPjBjZMp2yDoDTUMsc1l5gTSgMS3pFw0Z5pRGgEX1EbrqRpLn5BYzFv1PUj72QXMJ4EYRD32tMgDMJeO-61-2-4f2BlJfCoZ3L7m8pTJSyZ3BE6K6ytjJsSuiJ0tWm6AqU3hK5-ELqazeYzHT-wjNB5_zmfmzk9evQ0JHRVG03oSvDUncW2HI1jQlcpl4SuvF4w6uYERv-oZW0wHzG9qUuU1sDoWyu0nzdV2a4xKpDlqIeksgKz76hJdHdynoHQ1U7p74SuLBobZFXlhtzTQMmn-vhfRuit-3XQcpmJOkcg0ZKJjdLcFiWJ7of6jdUOpeHOLTqrOXT6c2P1fzr7wqX733bG7fuhqlPBMzdlTZtLC1tw_fEdiTopgN5Sc2MAs-_siTDLs4NkN6Bl__XRPbhV-gkJnb0ouXVmsn9Pb0DN-cX7j5p-8Oe9-glWg3RDZ9sgxY2zyJm7hy5hG6DMD82Gzwid-cXdHxQQOhWFcUKDfdr1zeEwAn9otLWWIAoTbN3Eg27-xUsSL_1ls798mCZw-PXgPDxoewTxsbH24fasVmmV1xnuDWZY_vnSiBYTEi1iEi1gx7Rf7NECFh0dNux4gvEcgqf5dnL3U1MHMrn_7_44c3xfn5F2Q9mExltC43Op--0VGZqnPxHhDi3jwsBaabAFwq5QAsFqliGkLPt-7EGiZd7IP2GPdz6t-1H1vcQmywhdPcymyfR6JLisH0YbWRO6Go8JXQXB81PLoc6jtNTcCqfcGkJXxorEYlml9TooSLSgU0qiReQUlcq6pQBLJoSPSWi8QeullWb6MUnr9Rqf0wuh8VNOOXGfRzCxjxX622bJp0RpvuGSiUSg9BTTW9RHNnLGcSEox-G1O4_7WC6MqcsWzKTRMXYmRKIlie6aqyV7OEDoD74Gh46TB8ffrcx8GJeLqhv3tf3Cvjtd10wYhFQzmRXnqXUxVZwa4-vXzdw9hH2tdgUXeKxYODhXF1XuaJ7-UKpyFJ9zlxM4rayuMQC4lxZ9RCSchEtTztL0YhrOHYdN-ir-s0_DLXUbq_SA4-ur6I7kS-VShySxZQVulTaxYJIxY0m0bLobAmvYTlWomfOUEncHdOgCDP-Bau0uuXtc_HQOs10KTc9gs9NrwZZVuxaksoD_qZlwmMpaiKdQdiveI0nHDszhtXFZZa8HSMytiAEOe5VW78eXf_ZRsSdlrcoPl342ot6lHzHLquOONdfG7leCHD1dAJ2ZVEEr-R4s5JTPPmHu71KH2VN-6kWsSXIUgCf7RMaZ7LGdO4p22WqSbGSdZA8PjaEniVS6ZCLhtqH14bteSrrb3_OF9PMRHoHtxtY2gNBb3zLoHPeZruT9LrDJ-KlBvnYyk5ybitms2MOa6XPh7j3j_8PzUrCF9Oka8HAdU1LPOTdBLPOdp9xZa2fRnXNonfQzX31RjYcc9als4xzVLqXUmL6Qd2S1bqfzVVPpjrXSPjJ1dJHVuotQ2nuiW2iG1j57uW9WGrcnc8zLzfv4maU_z168CQRw_4BZ7a9lSlouazSgJAguEeh40mr2ZvhcDBEXjoxPOcBSbfGZx5oeuaKjg9BFkhjE3Kc6yW9__H67_PYt-fT3rz7Bcb2d5i9GcX8RIk7FJnqfOs8RhX0o8KFiMse8CXhLlulmyRwrtt8yiprvd88UT5ItE4TOD47EA3voOAnFOzKL59H_h3X8ytYxyBn7b_5OhXZ7oERpYf9ZY60cS8b9-HZvLW9pIAMo_eQTfc9hvuL7_K-zrfKRKn-kyh-p8keq_JEqf6TKv2aq_Orp_EXT5Vdt9r05PhdDJPpJgUOy7DjuiVeiS3hxS6R3c68IK0lYnms0xu_8-QjYQ3Pu9t9fbkd7um93xvym6itShn5Q-9NUwcPT7JEeb6luFc_3e6pJ0uyVzpuN2AOwa6V3TOckWiYLvTGdNHP_6Txwep6703ROnvHGcf7blEc5Z0xXwwVPv6_hUdVgdtxmBZBpuCXT0JcIk2lofEnqEmzBDaDWSjeFvo47U_T1vnKoMvdvaudU_4xd7dxQhZVpvUuusu-oQdcSRiNdwohbGG3d66td7kSjDnuo01rauv80Vlmoq5xZPLS5NJYJAaNH2G3QgjDpSKNAZhCMWtsd0ziqtMtcLUczylRZKgkbWVdH9bj-5uP6XlbZQIht2Rb4-r-dHllRqhxqQm8f4KijOQcHeRjH_Z6mznocv6vC3iFruspvonwezdkV3oyn8XwaUzoLr4qbeZziJI7CNY3WaZjSNFuzNMombJKy-XU-v-I3NKRRGNHr8SSahWGQz2g6mUcRQ4zzNc7IdYgl42KP7hU3psab6Xg6i68ES1GYrkxe3_i66LTeGHIdCm6sOdxmuRV44_NjXwQeLboq3Q4RMrmDlY9xKmW45VsEtYbXFrs3BeZDdbFXtRY3T8rBuS3qNMhU2U5-V9NdafVvdB5h5dV05Oo1_V8AAAD__yrpm44">