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

    <tr>
        <th>Summary</th>
        <td>
            Catching silent spaceship operator<=> occurring via implicit conversions in C++20
        </td>
    </tr>

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

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

    <tr>
      <th>Reporter</th>
      <td>
          higher-performance
      </td>
    </tr>
</table>

<pre>
    Hi, there is a particular dangerous failure mode in C++20 where `operator<=>` succeeds through implicit conversions:
```
#include <utility>
struct S {
        int x;
        constexpr operator bool() const {
                return x != 0;
        }
        friend constexpr bool operator<(const S& a, const S& b) {
                return a.x < b.x;
        }
};
int main() {
        std::pair<S, S> a(S{1}, S{2}), b(S{3}, S{4});
        return a < b;  // Returns 1 in C++17, but 0 in C++20
}
```
The crux of the issue is the fact that certain parts of the standard library (such as `std::pair` and `std::tuple`) use `operator<=>` whenever it compiles, even when it only compiles due to dangerous implicit conversions. Identifying and fixing this issue can be quite painful in practice.

I believe _most_ instances of this failure mode can be identified by modifying libc++. Specifically, this can be done via a safety check in `__synth_three_way` that creates a derived (or wrapper) class from the user type, suppresses implicit conversions via `template<class U> operator U() const = delete`, and then checks to see if the compilability of comparison operators is uniform across all comparison operators (including `operator<=>`). If it is non-uniform, then chances are high that one of the comparison operators (such as `operator<=>`) is occurring through an implicit conversion, while others aren't.

While this method can have both false positives (e.g., classes whose implicit conversions are compared consistently with their own operators) and false negatives (e.g., `final` classes), they are relatively rare, and the code can usually be rewritten in a better way as to avoid them. For the rare where that's infeasible, it's also possible to add a whitelisting mechanism.

Before going through the effort of preparing such a patch for incorporation into libc++, I wanted to ask:

**Would libc++  be interested in such a patch that detects most such cases?**  

Note that such a patch may slow down compile times, due to the need to perform multiple SFINAE checks across all comparison operators (and possibly through implicit conversions), which may result in many template instantiations.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyMVk1v6zgS_DX0pfEMWUrk6OBDPl6wucxhs4M5BhTVsnqHIrVky47-_aIpOZF3_BYDGIlEit3VXcUidYx0dIgHdf-k7l82euTOh0NHxw7DjwFD60OvncFN7Zvp8A9S-TNwhwGBImgYdGAyo9UBGu2OGPwYodVkx4DQ-waBHDyr_EnlT3kG57RSlZkfMGj2QRXPqnhRxU9VZhBHYxCbCNwFPx47oH6wZIjBeHfCEMm7qIpHlb2o7FGV2fKbX_OCnLFjg6CK55HJEk8SOM1GDqNheAe1f1q-zypyDJ-q-B4w3kXGzyHABR_U3luVP6i8gjR7FUBlVUAeg4NPUPlOFS-QreOp_cvXcxsIXQPfKSQyrPuQP8wZ3lVegpZGr95rQXA7t95-SslQbz9vJ9-_fI1Lyb0mt5S0Dhi5kd4Wj4MmwfMuCN5V8VOwPLyr_dNOIqXB_VOenit5rZfpYjV9t0yv8FzQzlhV8QSg8leVv8I_00yE3Uosu30KPTJkVxL6LumWCP7VIZgwfoJvRaVAMY5JqfLSasPAnWYwGFiTS-qNl28ja9fo0IClOugwgcof4mg60FEUe92eMgPtmqtxHgeLgiSvYIy_Vvm5Q4cnDJB03Q9kMUqteEKXJmXCOzt9zUIzIrBf7bBbG2MLbw06pnYid0zoWvqUR-4oLp0w2kGN8J-RGGHQ5NrRSnuHoA2Twe2FLfn7BjVawhPCR-8jfwA56ZHBpWX0Pzt9CU4zCsIG6klmFkSWajOzuIX3AQ21ZLS10-woFC_rG-8QTqRBQ9Qt8gSmQ_OnwFRl9vERJ8fdB3cB8eOsJ2npTGpAzSim1GCgEzZCoA9wDnoYMKQdbHWM0AbfJ8bHiAF4GlAgxHEYAsaIt7ubEKkyY-wHqxlV8TxH-112yJdd_H7tFcULNGiRZ108J1ZYKE4lRSE1IgLNCpz51nWyLumxDOhA0buvDMIkjI7El0Gb4GMEbe3tT1X-MHui9P8XelR5tYW3VkRHEZx3P5boi9ML1pl0HRDkYJjbLSz5b9y3cq92zy8yS0pvzBjCLNTZ9rW7RYHgOXdkEbwcQAmPU_mer0T7R_oi6alH7nyTZNXpE0LtuYNW24gw-EhMJ0wwcXvcJrcVPjHCufMRb4tAWjBXi7OVU2R0bCc4E0tjkAL486oPUmTaiymvw6P-S15VZi05bUXJC4bFWbnDKeUMaNM6O0HQAVdSAnPZemMcZTvJFgp4DsQsViKGWyMzBjjrSdhgD_rkKa3ut_DqQ4ojcZfzWfhV-T4CuRZ1pNqmjDQPahu9NDCNp2hNA1qoYbQUWZjsUURDsb_i5glbHxCOfk225Ma29YFFTkNAkZI7wiweGDSbDlofgJzxYfBBM3kpjP3KUgTfG5y1Y2wSpvjn90VhuR_I7w8_2ma1DpJjOcaAUZaSu06cpN4go-EI4oLztNFCUvE6BwVYJ_rN89zC60i9niBaf4ZG9LFYOzD1s_svFi_dcDjXsNy-oB8t02AR3l_ffnv8efGOv7H5RSMLU9P_v1TNejt3tCANGEfL0o5euwkurrccAUyJhLjdNIeiqYpKb_CwK_e78q58qPJNd6j0_m6_21Vlta-qurnPy7as8navd01WFFW7oUOe5fkuz3e7h3xX5NvWVPe6uNe78u5B73Wt7jLsNdmttad-68Nxk46ww31V3hUbq2u08XJrDQf56Ec9HqO6y0SE8XsZE1s8PAsJSVdk0THEQRuMHQ3wF2taOZKY_k0jWF9JNmOwh455SHfTdKU5EndjvTW-V_mrIFn-_RiC_zcaVvlrqiaq_DUV9N8AAAD__3MYyQ4">