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

    <tr>
        <th>Summary</th>
        <td>
            Flaw in libc++ impl of LWG 2905: `std::unique_ptr<int[], const Deleter&>{nullptr, Deleter{}}` spuriously accepted 
        </td>
    </tr>

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

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

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

<pre>
    
libc++'s `std::unique_ptr<int[], const Deleter&>` will spuriously accept constructor calls with `(nullptr, Deleter&&)` arguments that should be rejected.

These calls should select the explicitly deleted `(pointer, A&&)` constructor, but don't because of the way that libc++ splits apart the pointer and nullptr_t overloads in the array specialization of std::unique_ptr.  Thus, instead of selecting the deleted constructor, the case below selects the `(nullptr_t, _LValRefType<_Dummy> __d)` constructor.  I believe it was the standard's intention that the explicitly deleted constructor blocks (i.e. is selected in preference over) the lvalue constructor in such cases.

I believe the single-object version of std::unique_ptr does not have this issue since its (pointer, deleter) constructor overloads are simpler since they don't need pointer convertibility SFINAE checks.

```
#include <memory>

struct Deleter { 
    void operator()(...) const { }
};

int main()
{
    Deleter d;
    // nullptr call below is spuriously accepted; should be rejected
    // as a call to a deleted ctor
    std::unique_ptr<int[], const Deleter&>{nullptr, std::move(d)}; // Spuriously accepted
    // For comparison, this call is properly rejected
    std::unique_ptr<int[], const Deleter&>{(int*)0, std::move(d)}; // Properly rejected
}
```
```
Via godbolt: clang++ --std=c++17 --stdlib=libc++

<source>:14:5: error: call to deleted constructor of 'std::unique_ptr<int[], const Deleter &>'
    std::unique_ptr<int[], const Deleter&>{(int*)0, std::move(d)}; // Properly rejected
    ^                                     ~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-trunk-20220906/bin/../include/c++/v1/__memory/unique_ptr.h:411:3: note: 'unique_ptr<int *, true, void, void>' has been explicitly marked deleted here
  unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
  ^
1 error generated.
Compiler returned: 1
```

I believe a possible fix is to provide a second explicitly deleted overload that takes a nullptr_t.  The existing deleted overload in question is [here](https://github.com/llvm/llvm-project/blob/7fe475756b26080fe0bb02e8e317662ccc9a01f1/libcxx/include/__memory/unique_ptr.h#L411).  It might also work to alter the _EnableIfPointerConvertible SFINAE helper to accept nullptr_t, but that might have farther reaching side effects.  Regardless, the decision to keep separate nullptr_t overload seems to be for an extension to accept NULL as an argument, so those need to be kept if that extension is to be maintained.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzNV9mO2zYU_Rr5hRhDkvcHP8zmIsAgCJI0fTQo6cpihxZVkpqlX99zKcnLjFMkQR9qaCzbIu96eO6ZzBSv6yi-i-JrrbI8Sm_CtXAimsfOF9HkGldbq79a2jbeRpNbVftodhPN7qL0VuSmdl7ckSZPNkrn0eQeG8Wz0lq4prXKtE6_Cpnn1PhutW1zb6zIpdYOC33FrqJ0WbdaswdYPbHH14pNSrtr91R7J3wlvXCVaXUhMhKW_qTcUzHu0ujev1bkqPfRL3UwmnvsJkEvjVa58oisCK6KPobGIDsKMVyfeT-JnB9mrReFqVEojxBy2cKZKYPtZ_naRXisJyqhFQKXjbRdAL0fIetC9HlvvTBPZLWRhROqDsuktbDmGsqV1Opv6ZWp2c-FxoyF-Fq1joNTCJVkERaGnFW9C-aGXN8kw49yiQwy0ua53-PCz2ed2XpevX34JvVnKr--NgQ0bO_a_f4VbRfbbfG-WAjrA9tV9ERCeVSnM-w8Upe2CFDjWtQht1C473ToFDyZNvkjMJou1ZjGQrk-aixD6RpLJVmqcwolRVTBpn6SuqUzO1js2rwK6bszAB2jDuGihJquTMZQE7Dpvt8JAIOcqI0XlQzbEZ1yrg1Wcq5CCPwEasUA99VZcEc4SMub940GZDojCOr1gMCakPcAKVjAPq8yBcy9ii-bDx-v70VeEQp2liH3tru6r-kElnVboOuT2z3tjeW2nu7oIhtOp4gWN6J7IPB6MgqQa8jKAKslYyFdjsfjQ1rdhsVdbxIfJjen5hG_2EtV95v7VTdHF4Pj4rCRf43SDa7hGIUz3yOZYfGWg4g3X2CPd_YAVNkZ8wafDijk7A5rf5EhFzcnZHewsUfDkXs4RaE4QyhfLiTxNtwNU6rZg2GUY1jcdsALCeDeWG4NDLzP95dz4NOHVSmgs4p_LJNPl8M4guINJs-_flNS7EyRGe3hRORa1rueYa-ugvO7nnGTRfcLOBg_nky2U_xPbp1pbU6czeQ6meJtxnbJWvSYHfTdv8RAOPvMXT9ZO9EXL138r-ofcDS7Fz_yihb3_8HVU87GNEhgw8BVILcrpn1jOcdN6O4Vyl0_XqVxmsarGMN4kzE_bJhVNj1d8dpBt2yeErxttz19pZuTAVmhMNMkwfuEmwuCJr6jF28LL0JNcYJsS3xnajvcQ_dA7Q7sQfXpoNpL-wiUDGipMIKG8p54SJfbTw2GZROG6Y0sPv_rPAUZ3_UmT1gPzeo-Jh1axY5qZt6DCrrtK4pG-9bWzHrXIrl8yN7MO4lR4pzKNIlSvTB54AiAP55UwQ8dAY3FpQE9zKt-istHYgo9iIegUHiyKxcUybttGMYokgtCAF4B_1BCPgLLyvvGMbgDjndQjW02BmzwReun4XaFMBnXjBNtMtwWJU0Xs8VsnqXzeBmXFGdZnNKSJsliPk_zPF_JOCkZNcwSLy9nuPoekNLJAyMpXbG8wdBSu8oLqZ0Rz8Y-hoGh-bSzdNje1xK1_FB-6gb07TCfUd9-OFekG15tBp18JrhYa4aKdm6CqCghJKvQXZlXXEzHzaGyZOWGoD7TDuJKk3ODwCugIYNogZdHogZ9xKwAYi7oTzyjfWg7BmRpWKaibdBog4E-zI-_PzyEOVkf1HmgIQOPBnoy6JLOyiOvV2WXyNGWGrzw3Pf4A4BHtE7m80m6XC3T2ahYT4rVZCVHHlij9UbLZwbKibhmXcR0_PDHbwJEGCj81_95ORvNwyNwLWgUF8TtBUUhRq3V65-GaBCFaNBmtlgs0lG1niaz5XKVJjItl8VkVshEzubzWZmVMknmVIy0xCF1a84gTWt67nQlPiOhkVp3NJnM43i2iKfjcj6Ls-lUFvPZMpmu8mgaE-qsxxzH2NjdyK5DSFm7c3iocTDd8aEECezQwnVXsJFs0VW7zisojEwWO7Kj4H4dwv8HQiaGWA">