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

    <tr>
        <th>Summary</th>
        <td>
            "Unspecified" parameter for the standard comparison category types' comparison operators might be overconstrained
        </td>
    </tr>

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

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

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

<pre>
    Hi,

Consider https://gcc.godbolt.org/z/ndrvzE8j1

```
#include <compare>

struct P {
    operator std::partial_ordering() const;
};

int main() {
    std::partial_ordering::equivalent == P{};
}
```

Clang + libc++ rejects this with:

```
<source>:8:39: error: use of overloaded operator '==' is ambiguous (with operand types 'const partial_ordering' and 'P')
    8 | std::partial_ordering::equivalent == P{};
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~
/opt/compiler-explorer/clang-trunk-20240620/bin/../include/c++/v1/__compare/ordering.h:62:47: note: candidate function
   62 |   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default;
 | ^
/opt/compiler-explorer/clang-trunk-20240620/bin/../include/c++/v1/__compare/ordering.h:64:47: note: candidate function
   64 |   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept {
 |                                               ^
1 error generated.
Compiler returned: 1
```

It's not entirely clear why this should be rejected, instead of  using the `friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default;` operator described by https://eel.is/c++draft/cmp .

https://eel.is/c++draft/cmp#categories.pre-3 is quite ambiguous about whether the code above should be accepted, or if it falls under the "In this context, the behavior of a program that supplies an argument other than a literal 0 is undefined" https://eel.is/c++draft/cmp#categories.pre-3.sentence-4 sentence. 

I am not sure what "in this context" means: does it mean that passing `P{}` is UB because it's not a literal 0? That sounds like a vexing interpretation: the very same overload is selected by e.g. `std::partial_ordering::equivalent == std::strong_ordering::equivalent` after converting `strong_ordering`, and I don't see a provision that would _allow_ this.

Ultimately it boils down to the SFINAE on `_CmpUnspecifiedParam`'s constructor here: https://github.com/llvm/llvm-project/blob/main/libcxx/include/__compare/ordering.h#L39 ; it excludes the standard comparison types, but not types *convertible* to those. Fixing that SFINAE would fix the problem.

Related:
* https://cplusplus.github.io/LWG/issue4051 
* https://github.com/llvm/llvm-project/issues/43670
* https://github.com/llvm/llvm-project/pull/79465

---

For some more background: in Qt we have defined our own `Qt::*_ordering` types because Qt only requires C++17. Basically, we've backported the standard comparison types. We want them to be interoperable with the standard ones, so they define constructors/conversion operators towards the standard types. Which leads to the problem shown by the testcase above (`P` is `Qt::partial_ordering`), tracked by https://bugreports.qt.io/browse/QTBUG-126541 .



</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzEV01z4zYS_TXwpUssCpRE6aCDJJuJq2Z3PdlM5agCiRaJDAhwAFAfOexv32pQsmSPPTuT1FZUNkWB-Oh-_fp1U3ivaoO4ZNM1m97fiT401i2lMDVqW9-VVp6WPyvGNyy9Z-lquG6s8UqigyaEzrNsxXjBeFFXVVJbWVodEutqxos_GC-MdPs_Hua_j293YLP0_Df85Jkyle4lAss2lW074ZBlD7dLfHB9FeAJWL4eRgAAbIdOBOvAB0mGZKtOuKCE3lon0SlTMz5nfAGVNT6w7LyU5ffX-3hVJkArlDlPf3HI-3vHUfzSq73QaAKw7J5l9_BEy2-PyO_f9nuAUwtTA-Nr0KqsGF_TrcPfsQoeQqM8HFRo6KxvIJhtvO1dFVHLVnOWrbIFy1aAzllHN71HsDuwe3TaConyih3j-WA44zkoD6ItVd3b3gPjczp7mGokhFOHNJpHOOFrrHOgaYznT7QpX1xBnAPLN38dSogf2uo__-sDbPpAsy4cK2wXGC-IXkqjG-Gx09ahozEKwSi43nwe8ZRP0hlPGS9K4kORJIwXZ37S3CFCjBf7MePFdnvhKy8uziQUrRln2WqSE_bGBqTvShippAgIu95UQVnz7NSMR6cAth8e15unp-3Pj_cP2-KXf_1ju1o_ws4pNHJgMR47B6W1-jmCl-jNvw7I5o0gLcBYPFbYRZRB4k70-poc0RA2ffi7cJv8EG6T_wdusN3uCbvtpu0-Gd9hpXYK5ZNwon2JX34L2o99niEeD1kKNRqyC2Vy0dkBcXAYemeQUgfG31CSx8B47gk2QBOUQ32CSqNwcGhOg5T4xvZaQolnhUFJfiqCR0gSCOg9ARAaBDZL_yx--7eYB4dvcW-WXhVJoq-cKlFCeXpVZRB1ovyVT9KJXaRn20FyC8Z3L2M8q0TA2jqFPukcjjJSwS-9CnijhaK0fYBDg6FBF_GprEQa3uMNrKIi5wZYrQO1AxVgJ7T20Bt5Xsk4fzRDQCprAh4DTacnJTZir6yjUAjonK2daCE0IoDvu04r9CAMCFf3LcmkPVtDY6BVQCc0pGQ_nbZTxBrOvx_DN8BIPJqApsLRBC63CbzgHYg2ss73DuFAxjLO1WsPObQoDJkB0qInYGhg8K6jXoTq4Cy9aP4s-vFpDSVWguqXuvL7xlmWFfBrBMj2RnrQ6jOCgD0eaT9lArrOYRBRN7JVhHmP7gRetPhcEOkojzqmBLEOkzohY364Yj0v8MFZU787n9wTu4COANqjC2fvXy-bpcQNKquPIK1hPA_gEQd27JVX9ozgIVJwK7S2h22E_kU-fNJBtSKQJqgApVXag7QHA8FGSP5dPP5z9QDWkBFvCh9ZkvtBDKgZsw4adFGhX3WCKjR9mVS2ZbzQen_5GnXOkuhQidC2ZLwYWq6CGp_j8UW5eKc-8OxDtgCWrckJPMbZPtrvgzBSOBIrWqc84UL9CsFX9iHS5tLArC6YlxoZXw0YWI8JFOo46J8IF0gGYHfqGM_pnC01ti-w_QU16fa1R-OvIak63Xv6T87gKMt48eG3n8hp73ucpNMxvLf6OwCNm1BOT7JZnv6Fjbpea8aLfDGZTW99HI1Gtz8Larpti9Bah1CK6nPtKP-IDcrAxwAHhEbsEc4yBLZ3QHxjs_RjGLKB8dUt0c_huaT7xwDW6BM4ShqHHjaDXI3zBNbCq0pofaLoHpDxfD9Y0VlHGfxNRiTwG8JBmEDTWgp-iYNQxApUaowt98tNrBmo5GO6nM5u3WZDVNTIq5iUl2rmIdiDcPIVTS-WNKpqQKOg5_aWYVRUDoa0iAYD-lAJfyk49J5CSjlo5A2kX8kUZe0ilhcnqs9vldSyrx0Sbj75EgZils4ePKXex1_Xn34ajflsOhm_rK_D9U4uM7nIFuIOl-N8PF-M81mW3zVLWeaTqZiPq2wxEdVUTsez-Y5nZYbZfLfbze_U8tIx8nGaj_NkLqYLPplPqpTzjM8yNkmxFUonRFB6o7yLHF8uZjzL77QoUfv44sq5wQPEh4xzeo91y0jqsq89m6Ra-eCvuwQVNC4Z5zcCR8WpI5FDEuSdde8S6FwdTxdtyW8fXkPeqroJRCuqLwNHBGXBXe_08s8n9-D7fsn_GwAA__9vfQkZ">