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

    <tr>
        <th>Summary</th>
        <td>
            std::is_invocable_r and std::is_nothrow_invocable_r incorrectly handle non-moveable return types
        </td>
    </tr>

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

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

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

<pre>
    Here is a test program involving a function that returns a type that cannot be move-constructed:

```c++
#include <type_traits>

// A type that cannot be move-constructed.
struct CantMove {
  CantMove() = default;
  CantMove(CantMove&&) = delete;
};

static_assert(!std::is_move_constructible_v<CantMove>);
static_assert(!std::is_copy_constructible_v<CantMove>);

// A function that returns that type.
CantMove MakeCantMove() { return CantMove(); }

// It is possible to call that function and use it to initialize a CantMove
// object.
CantMove cant_move = MakeCantMove();

// <type_traits> agrees that it's possible to call the function and that it
// returns CantMove.
using F = decltype(MakeCantMove);
static_assert(std::is_invocable_v<F>);
static_assert(std::is_same_v<CantMove, std::invoke_result_t<F>>);

// Therefore it should also agree it can be invoked to yield a CantMove.
static_assert(std::is_invocable_r_v<CantMove, F>);
```

clang 14.0.0 (with `-std=c++17`) [is happy](https://godbolt.org/z/orTGYcK8E) with this program using libstdc++. But libc++ is not; if you [add `-stdlib=libc++`](https://godbolt.org/z/GasonE7b5) then the final `static_assert` fails:

```
<source>:26:1: error: static_assert failed due to requirement 'std::is_invocable_r_v<CantMove, CantMove ()>'
static_assert(std::is_invocable_r_v<CantMove, F>);
^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

For what it's worth, [gcc 11.2](https://godbolt.org/z/PMfhW6qYr) is also happy with the program.

I believe libc++ is in the wrong here. The [definition](https://timsong-cpp.github.io/cppwp/n4868/meta.rel#lib:is_invocable_r) of `std::is_invocable_r` is
    
> The expression `INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...)` is well-formed when treated as an unevaluated operand
    
with `INVOKE<R>` being [defined](https://timsong-cpp.github.io/cppwp/n4868/function.objects#func.require-2) as

> Define `INVOKE<R>(f, t1, t2, …, tN)` as [...] `INVOKE(f, t1, t2, …, tN)` implicitly converted to `R`.

and `INVOKE` [defined](https://timsong-cpp.github.io/cppwp/n4868/function.objects#func.require-1.7) (in this case) as simply `MakeCantMove()`. But the [definition](https://timsong-cpp.github.io/cppwp/n4868/conv.general#3) of whether an implicit conversion is possible says:

> An expression `E` can be implicitly converted to a type `T` if and only if the declaration `T t=E;` is well-formed, for some invented temporary variable `t` ([dcl.init]).

But we saw above that `CantMove cant_move = MakeCantMove();` is accepted by the compiler (and I think it's supposed to be, due to copy elision rules).

For the record, the reason I care about this question is that types like `std::move_only_function` (I'm using an advanced port to C++17 of this) have their members' overload sets [restricted](http://eel.is/c++draft/func.wrap.move.ctor#1) by `std::is_invocable_r_v`, and I'm finding that it's not possible to usefully work with functions that return a no-move type like this under libc++.

I believe the same bug applies to `std::is_nothrow_invocable_r`, although in that case [libstdc++ also does the wrong thing](https://godbolt.org/z/GhhPWEe5T).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy9V9tu2zgQ_Rr5hYhgy_HtwQ9O7HSDot1iEWzRJ4OSaIuNLKokZa_79XtmJPkWp81iiwa2owvJOTxz5sLYpPvpH8oqoZ2QwivnRWnN2sqN0MXW5FtdrPFiVRWJ16YQPpNeWOUrW_CEfanqZ4ksCuNFrMTGbNVNYgrnbZV4lQb9WdCdB932d9itP0kQ3dGnfhr1dZHkVapE0L-nZZfeSu1d0F-czY4e8BGzN1kO6zn1rbiXhf-AESIYNUbF4VkQjYNoAtNzkaqVrHIf9K8NOl4O-dNOyZVXhxnBaH68bhBIr5OldE5Zz7Z6zjMx_Zl2S8K9PODWca6WW7BwMAYKoslhyZ8slphy__bFLli97me-IcIbQg9MfpDP6pLC0V0z74JcmBTEzEuzj57UVxrnCK3wBi7N89rqAZAsUlE56NTTAF1or2WuvyuI8GDndFETf1WJvwQMrXimm_32Ev51Xl4oUsi1VaohRsMJo6v41Tn8dvTp0i3FLYwGcOUo7h4adSU5mQfCc8CvS-JUDxTGiWxl8PATMZ3OdHJzoZ3oXhwHYN1ntbTKIVqWvl37B_J6ypBoVsayE11mqjwVMnemZpMewj0Ux_XSKTG514pGXfLztg3bF-gvt39IRqdwk1yC_N5t2A27AovvtM8ExtywlXmTt3ojmkaKH9xBvpksy30wmGN85n3pCA5ve23S2OQ-NHaNu-_4Gvv07kvyfkxIBC_uMwqAJu_Wvs91DHONrVDcVZ4eNfcUL8h5FFJ6JfamIhAyTVuUGAmgx_GE9E3Q3klnisUoHhA0CLioVawLmdPa57QPu2Ilde5eS_DNbf_emcomnHn6M2TN_qyHr1DWGksXZ6vykvB9WnEkWfWt0lZtVOEFhdkb_XzM9U1Yg-vRL5bOYCFO_4LR4nd8XpctdCV2JwlpZ6zPCDm0sU4S0euF0dtU8OnDKvs8_PbFkgqoMaAgZYG3clWtWsNTBI8I3lwr0H4uVV3LaGcNhE1JIKRcQLhQbDmVm-IaMq83kOP6JinLcA3DVRxqg-e435X4X9yOh3Dvw0Z5GVqVo4lg5V-4knZhVrV-r_qalKxdW-7hyka4C4ap_imR5BxlcQx8_Pj3n-8h5Pu_WA9jys5bmVP6K-onJBKwfnwxs-sn5G93eB2GIQ1iq2Kn8vwGWXED0e844qySaF6EBPGFqAqFVSp-YkplUUgugbb56RwaVo8VZZKWZnRi_4PjtpKFdWF14JoehU2A3kTEsnRniQAEztnyNeJWRJLv8W_EMl1EwbgbzIb86GPDEFjABoixwfxkmTfP15sy14n2-V6gKdoi5uvCgnd_4XumXyrSRxOY_Huo64UjriPRmAMFmkikUzWfwtEG9gTrSrcC_FwZ_K-MJqIpXKsCWqOI6jfhA23CjCVNtpw2jHJonHZwTu5fFAVoYVZcxBJz3Nb8V_zUnDEw8ondueJWyhQYh2vaOAWatNI3iz4J1MX5gvL0iwAjZeBKOLPhLgNVhayoTWmstHuxlVZTSqB1uL4Rz-A1yUMillmdnEmG2N_RjndCxlRwuMnD1P_UctZAZZKokgDFe95YYjYlaqElFLTpRxJH8dzmd1eVYLxmKeYS1dRMOgEIJGKm2VY5Ms8FaioVZMGqxFhmpb6j6g8ziUSPhu2wsgDsW4VzYePkw1nAIck_q7OsyucYcs2ylXzD4SMAt40N3C3TrSwSIAft3M7fty0VCY1MkuYyyXQqbcVGbWLoDKsImLC5kalwynNqgJ681XzQPIj-oHml4DlHoq4tpFaufBOS4c7KMiTMYeLRiUT9HpmN9z-oFOgKqOm7ZxHWu0LIpbSv07MAnUdPzwM4uKyqHJJFTX6ua2jLkDs9akHthblhsbDqmWF2QVWkEMKxrL5Sd8mN1LaLuALTJUKKTinmckfAl1mzu6iBvK_cozFfZ3XN5tO149xy1o_WHUFq-AjUFnYS5_qNbWaWffq8UIMnEmYnnfbTSX8iOx7hr6avUM-U_2QTQA1BQ9WURjJMAP2FKZhRjuuGZtZvp7L59AJpnRYReLjJ82377wbdDqVu3GrnKgqoh8GgfzvsZFOl5G0cjSbjqHerJsPJMFqNR8M4SruRmoy7cSeX8I6bgsMgigq1E7wErsFVR0-jbhR1B91Jd9S_HaBFS8ZYbjiM0-Fw1RsNgtuu2qAlDgkHUdixU4YEDzu8RJh7d3yJtlavC6XYHNaXFfxpp19lYmInO2x6ytD_BeA9mFc">