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

    <tr>
        <th>Summary</th>
        <td>
            clang-analyzer: NewDelete potential leak in shared_ptr (false positive?)
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    Hi,
I have this kind of program:
```cpp
#include <memory>

struct A;
struct PtrWrapper
{
    std::shared_ptr<A> m_sp;

    PtrWrapper(A* t)
        :   m_sp(t)
    {
    }
};

struct MyClass {
    MyClass()
        : m_ptr(nullptr)
    {
    }
    MyClass at();
    PtrWrapper m_ptr;
};

struct A {
    MyClass at()
    {
        return MyClass();
    }
};

MyClass MyClass::at()
{
    return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
}


```
Running this code through clang-tidy with the `clang-analyzer-cplusplus.NewDeleteLeaks` check produces this warning:
```
<source>:33:1: warning: Potential leak of memory pointed to by field '_M_pi' [clang-analyzer-cplusplus.NewDeleteLeaks]
}
^
<source>:32:9: note: '?' condition is true
        return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
               ^
<source>:32:33: note: Calling 'A::at'
        return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
                                       ^~~~~~~~~~~~~~~~
<source>:26:10: note: Calling default constructor for 'MyClass'
                return MyClass();
                       ^~~~~~~~~
<source>:16:5: note: Calling constructor for 'PtrWrapper'
                : m_ptr(nullptr)
                  ^~~~~~~~~~~~~~
<source>:9:7: note: Calling constructor for 'shared_ptr<A>'
                :   m_sp(t)
                    ^~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr.h:214:25: note: Calling constructor for '__shared_ptr<A, __gnu_cxx::_S_atomic>'
        shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
                               ^~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:1469:17: note: Calling constructor for '__shared_count<__gnu_cxx::_S_atomic>'
        : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:928:4: note: Calling constructor for '__shared_count<__gnu_cxx::_S_atomic>'
        : __shared_count(__p)
          ^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:917:16: note: Memory is allocated
              _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:928:4: note: Returning from constructor for '__shared_count<__gnu_cxx::_S_atomic>'
        : __shared_count(__p)
          ^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:1469:17: note: Returning from constructor for '__shared_count<__gnu_cxx::_S_atomic>'
        : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr.h:214:25: note: Returning from constructor for '__shared_ptr<A, __gnu_cxx::_S_atomic>'
        shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
                               ^~~~~~~~~~~~~~~~~~~~~~
<source>:9:7: note: Returning from constructor for 'shared_ptr<A>'
                :   m_sp(t)
                    ^~~~~~~
<source>:16:5: note: Returning from constructor for 'PtrWrapper'
                : m_ptr(nullptr)
                  ^~~~~~~~~~~~~~
<source>:26:10: note: Returning from default constructor for 'MyClass'
                return MyClass();
                       ^~~~~~~~~
<source>:32:33: note: Returned allocated memory
        return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
                                       ^~~~~~~~~~~~~~~~
<source>:33:1: note: Potential leak of memory pointed to by field '_M_pi'
}
^
1 warning generated.
```
Is this a false positive? If I change the ternary to an if/else statement, the warning disappears (the generated assembly doesnẗ change however).

I have reproduced this on the Compiler Explorer: https://godbolt.org/z/MqoTh9xd6

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWd1vozgQ_2vIi5UofCTAQx7y0eoqbU-r3ZVO94QcMMFXx-Zs0zb719_YQEhS2rRV1WvvFhE3sfHMb748w3Qtst3sN-p4S2e8csbzK1TgW4J0QRW6oTxDIkelFBuJt44_r59xpuP6TsuymfF8ylNWZQQ5_nJLtkLuHP-iWbSj0rJKNZo7_uJo4quWf0hclkQ2T4fNOoJL6cxw9eeqwJJkSakl0IeJC7RNVLmn1e04IOdFgGuOtOPF3bq5gB6MloAXHS8fcXfCVYtpdcKqAX-9WzKs1PG2ZhJo93LeWim8iFeM2W9n2R8QRVg3dP1Fn9AN9T3Yx4DPeyF31PsRmUsSXUl-IqT_PK21bNrN1rTHPI_4NbysTCNjL-R4ruOvUKM70OflweoQ_KKlZlXdD7IDeDi2Pl3__FZxTvmmjoNUZCYipKg2BUoZ5puhptkO3VFdwDz4PISCncYcs91PIodpySplPqPfyd2KMKLJF4JvFDyJ0oKkNyaosiolqmZxh6Xh9zDEmp_-UolKpsQElT_3fRhcI2G3D30VmnBNMUMMOJm4reMQlYJyTTKkBVrvUE4Jy0CPYXKdlBD3IXImi-ein6xOVTi56EfowRAbWBxgmb_ACaxl-KWCZ1RTwREIDu5Ieh3sjY2Ojq8ncVv17oEvMWPGFQD6vPPY8F8A_dhlhAlfcvdJ7k2NT437JM9IjiumjeHq40NIlMMHtLDHHfYjPntavFCcPuSuQT7pA94D-DA_PIL53CH9auX3gTcxEj4T-4Mk-KQIj2S45-FvsvqlKGH3ZSq2JWVwMJD7kglpdHe5SdOh4rhUhTCPMLquJ2G8j6bJNBiCGNX9cMMrmHL90Xg0hi-j0cOhKR0MI8db2LvbsKYa_Oayk31UGG91AzM-1-pJcqI7b4mSBKAl6f19HdTJ9wRrsaVpn14PdntR8mdp6ookKdvoPSGf_Cgtkah9JFwcJ_MnrhfH8qeyXbLGilgDusHUuL77XN_fqzgVFddGyS8wn7XRdWs-axTrAdeJJHlNsJlfIr0rCcdbAskpwVLiXWdQy8isN-fYU2H1NqZ82_tTOEYMuvXnwbu5xTGBvXucGPb1tvwcSrdxaBPpXuvXdfUINRqoX6QYSsg-d7dlJLKlDrlDyfey1mR3GH41UQfB9uXoUDxTBLxf7HwO-zwMim-2sjJhkUux_RUb75up3kP7vxLWB_aPR6vQF3jG_6cYPfPOc15n7_7qc-4V8zzkj_am2fOCfyLEB3_P7-nN1AKQrCtRmqbXf60703X8WtFf2-57rIHntr1EtCGcSKPLUW8v8qppWWKUY6YI8FNU01tidHiVoyuUFphviG2MaiI5BkyABXNEczhCidmjNNDfEpPGlvbBlndGlQkZLBUy4QsrezQILEC2a7ZDmSCKOxeus5g7cdjyK8QduTXBFre4D_-hIUnTcM1q9IJbvssmp6CLNqeAagutS9uc9i5NNhHZWjA9EnIDv37C5_pv8aOI77NpzWFAZu50GgW-F0XxIJv5WezHeKCpZmR23Fk11PctVdDckQkpPzjajfgP9AuyDSrJZicAqS6q9QjSo8mA7Lb9MwSJ_yKpyYtUqYqYBDaJ4sgdFLOApIGbpV7oTUMycT038oPMT9NgmpP1xI8HDK_BUjNnAmnQM5W9JQHfnclqQGfe2PNc1w1c3w-CeDTOg3wcBhHxgzAdx7kTjMkWUzYyOIzmBnJmIa2rjYJFRpVW3SJYlm44IZYd0MeVLoScqd1uJweW8cwC_wczyVv8">