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

    <tr>
        <th>Summary</th>
        <td>
            [clang++] Bugs on overloading operator== and operator!=
        </td>
    </tr>

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

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

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

<pre>
    I'm writing a generative meta-programming library. Below is the code that triggers the bugs.

``` C++
// test.cpp
#include <concepts>
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>

class CppExpression;

template<typename T1, typename T2>
concept same_after_decay = std::same_as<std::decay_t<T1>, std::decay_t<T2>>;
template<typename T>
concept is_cpp_expression = same_after_decay<T, CppExpression>;
template<typename T>
concept convertible_to_cpp_expression = is_cpp_expression<T>
 // below are for generating literals
 || same_after_decay<T, int> || same_after_decay<T, unsigned int> || same_after_decay<T, long> || same_after_decay<T, unsigned long> || same_after_decay<T, long long> || same_after_decay<T, unsigned long long>
 || same_after_decay<T, float> || same_after_decay<T, double> || same_after_decay<T, long double>
 || same_after_decay<T, char> || same_after_decay<T, char *> || same_after_decay<T, const char *> || same_after_decay<T, std::string> || same_after_decay<T, std::string_view>
 || same_after_decay<T, bool> || same_after_decay<T, std::nullptr_t>;

class CppExpression {
public:
 enum class Precedence {
        LOWEST = 0,
        COMMA = 1,
 ASSIGN = 2,
        LOGICAL_OR = 3,
        LOGICAL_AND = 4,
 BITWISE_OR = 5,
        BITWISE_XOR = 6,
        BITWISE_AND = 7,
 EQUALITY = 8,
        COMPARISON = 9,
        SHIFT = 10,
        SUM = 11,
        PRODUCT = 12,
        PREFIX = 13,
        SUFFIX = 14,
 HIGHEST = 15
    };

private:
    std::string expression_;
 Precedence precedence_;

    CppExpression(std::string expression, Precedence precedence = Precedence::LOWEST) : expression_(std::move(expression)), precedence_(precedence) {}
 CppExpression(const CppExpression & other) : expression_(other.expression_), precedence_(other.precedence_) {}
    CppExpression(CppExpression && other) noexcept : expression_(std::move(other.expression_)), precedence_(other.precedence_) {}

public:
    static CppExpression create_expression(const std::string & expression, Precedence precedence = Precedence::LOWEST) { return CppExpression(expression, precedence); }
 static CppExpression create_termial(const std::string & expression) { return CppExpression(expression, Precedence::HIGHEST); }
 template<convertible_to_cpp_expression T>
    static CppExpression create_literal(T && value) {
        if constexpr(same_after_decay<T, int>) { return CppExpression(std::to_string(value), Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, unsigned int>) { return CppExpression(std::to_string(value) + 'u', Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, long>) { return CppExpression(std::to_string(value) + 'l', Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, unsigned long>) { return CppExpression(std::to_string(value) + "ul", Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, long long>) { return CppExpression(std::to_string(value) + "ll", Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, unsigned long long>) { return CppExpression(std::to_string(value) + "ull", Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, float>) { return CppExpression(std::to_string(value) + 'f', Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, double>) { return CppExpression(std::to_string(value), Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, long double>) { return CppExpression(std::to_string(value) + 'l', Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, char>) { return CppExpression("'" + std::string(1, value) + "'", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, char *>) { return CppExpression("\"" + std::string(value) + "\"", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, const char *>) { return CppExpression("\"" + std::string(value) + "\"", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, std::string>) { return CppExpression("\"" + value + "\"", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, std::string_view>) { return CppExpression("\"" + std::string(value) + "\"", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, bool>) { return CppExpression(value ? "true" : "false", Precedence::HIGHEST); }
 else if constexpr(same_after_decay<T, std::nullptr_t>) { return CppExpression("nullptr", Precedence::HIGHEST); }
        else if constexpr(same_after_decay<T, CppExpression>) { return CppExpression(value.expression(), value.precedence()); }
        else { static_assert(false, "Invalid C++ literal type"); }
    }

    const std::string & expression() const { return expression_; }
    Precedence precedence() const { return precedence_; }
};

template<convertible_to_cpp_expression T1, convertible_to_cpp_expression T2>
requires is_cpp_expression<T1> || is_cpp_expression<T2>
CppExpression operator==(T1 && lhs, T2 && rhs) {
 return CppExpression::create_expression(CppExpression::create_literal(lhs).expression() + " == " + CppExpression::create_literal(rhs).expression(), CppExpression::Precedence::EQUALITY);
}
template<convertible_to_cpp_expression T1, convertible_to_cpp_expression T2>
requires is_cpp_expression<T1> || is_cpp_expression<T2>
CppExpression operator!=(T1 && lhs, T2 && rhs) {
 return CppExpression::create_expression(CppExpression::create_literal(lhs).expression() + " != " + CppExpression::create_literal(rhs).expression(), CppExpression::Precedence::EQUALITY);
}
template<convertible_to_cpp_expression T1, convertible_to_cpp_expression T2>
requires is_cpp_expression<T1> || is_cpp_expression<T2>
CppExpression operator>(T1 && lhs, T2 && rhs) {
 return CppExpression::create_expression(CppExpression::create_literal(lhs).expression() + " > " + CppExpression::create_literal(rhs).expression(), CppExpression::Precedence::EQUALITY);
}

int main() {
    auto var_a = CppExpression::create_termial("a");
    std::cout << (var_a == 1).expression() << std::endl;
    std::cout << (var_a != 1).expression() << std::endl;
    std::cout << (var_a > 1).expression() << std::endl;
}
```

**Compiling this code with clang++ takes extremely long time:**

``` shell
$ # clang++ 20.1.2 | Apple M3 | MacOS 15.4.1
$ time clang++ -std=c++23 test.cpp
clang++ -std=c++23 test.cpp  132.19s user 0.29s system 99% cpu 2:12.60 total
```

On another machine:

``` shell
$ # clang++ 18.1.3 | Intel Core i9 14900K | Ubuntu 24.04
$ time clang++ -std=c++23 test.cpp
clang++ -std=c++23 test.cpp  184.87s user 0.07s system 99% cpu 3:04.95 total
```

While g++ performs like:

``` shell
$ # g++ 13.3.0 | Intel Core i9 14900K | Ubuntu 24.04
$ time g++ -std=c++23 test.cpp
g++ -std=c++23 test.cpp  0.15s user 0.04s system 95% cpu 0.202 total
```

And according to my observation:
- Call to `operator!=` is the reason of long compile time here. Removing line `std::cout << (var_a != 1).expression() << std::endl;`, clang++ can compile fastly.
- But if removing the definition of `operator!=`, then call to `operator==` will cause a similarly long compile time.
- Except these two operator, any other binary operator has the same effect.
- The underlying reason may be the concept `convertible_to_cpp_expression`. If we reduce the options of literals, e.g. remove all options after `long double`, the compile time will be short.

Anyway, I think it is a bug because g++ can easily compile such file. However, due to my limited capabilities, I can only hope that you will be able to address it.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWl1v2zrS_jXMzaCCRPnzIhe2E7fG2570bVL07JVBS2ObW0rUkpRT__sFqQ9bitIo3XjPKbCBgNac4fCZh8OPGYlpzXcp4jUZzsnw5orlZi_V9UKmKUaGy3TJuMA4vtrI-Hi9InScwKPihqc7YLDDFBUz_ICQoGHvMiV3iiWJlQq-UUwdPZijkI_ANZg9QiRjBLNnBoziux2qonmT77RH_Jl9Rn7xwILQuX38GaFLQpdgUBsvyjLXEvI0EnmMQMJFJNMIM6NJePtExqU2ClnSJdNG8XTXJTHHDNdGMd5tNDdccHMsRf4sEkxrWGTZ7Y9ModZcpiScFzKDSSaYwdJqyhKEh4DQBZx-0sJS6QdoluCabQ2qdYwROwIJb0CbmIQzEs4KqXb4yyantTYkXDwE1hRdQJfMDWOf-XO4mji4XkdZtsbaqQJIC521bEdsud9_mEimB1SGbwSujewa8gkQN6YzAmVwbFyYMYWwlaqOTBeIBhUT2umOF2S8eNYDnhoS3r6kladuzcQ91YV0Idbbak99q_ZLtqtOPfjYCsn6uBjLfCOwL-hauweCaM9UD7tWDQid9VGVqTav6XBad9Vu8coe6wPHx37ubqQUrxkgzYXIjLKr-7becDo2IyBjK8zyjeCR7erPANM8gUL3s8IIY0wjLBWh_Pt49-32_sEtQZ_QxZlkcffp08wJglIwu79fvf_DNdGm7se796vF7OP67ouTht3S2R83TjwoxfPVw7fV_W3Va9jsVUn_LMWjbnFldFyKb___6-zj6uEfrnHyxKXPsy-r-7vCiWlTev9htSyYCFpU3H_9VLQHzfbPX-5uvi7KPrQtu12u_ixEYdvcshZVXHxYvf9QTUQwLJXJ-Kae80zxg9tkZ6WwFYNw2jrXRafzSc_q_65ri46Rxo5OJ88btVHZadBBPkmK7kVYEToFEs4a0M7GSOQBCZ2cjzF1z6KBl05Ov5zF8dwS48-eoC9Wfmtd0BFIs0fVDcaJvEZbB4BCq9F2jqODyCcgGjhSiT_cwfgyO90AX42xvTe4AGKGRy26IoXM4Pk5XNHaDg3r0BuEx3gOCk2u0icUNo03YoCEcyi5_5kXBlXCmejtwivgtD0q128T29nN6Oc3oOqm88KslBcdQicPVUgdmMjrVXHaYvi2OAbtGDaofnodesHxmjUj1-UJSSfVuL25QKGxL6zW_es_wQeEzoHQcU7o-CJYq7vWG2AUl8LYvnm-AViaC0LpxRh9S6TiYki7b91vQu7FMFc3_rcI2O2lAvaUQPw3tqby79Ux-iYoL774ywTrBYwu3MaEUoennRHRiStntMO06HFJns-yuB4ODBcOznM-PIFf6V_Ug3Y2-pv68TRJfq0jDvZfiblO03_PGShLBy-gL1kOlxaXURYmdWkGoXTLhMZLHSzdJYsXqS61L8zdk8plDxI9bEKd1lugd56MTMqErBufHaS40q-Z1qgMoZNyGhZ2SlbpgQkeV6XwqpbpKseOk5bhOpuzP_plNRZgqXrmcrNccDZCZxb3nJVmXaFCd1a26J8CBeVu-TOdsoqu8F85V6i7q8bBWX2tU6G00kyxZIaKGalIeGMfOnkIqhxL7LXF9kCrBmUb6pSrM4bchHQl08-rnbI7N-D0SfxVuw0UGKHan_qYVN0mO9aG7d5ehlVRrQjHcop_x8mlwd9_ch3G_03uL6zc27_5zFrv_uppJf6MpwYSxmt4deWI5UbCgak1c1W75zGeCmuEUlafU-3KdCRzAyRckNCedZPacvlSoYuqQrm2gGksehsuFs4FDIe3r7Zakl296i7ffFP7LGSScWFParPnunhh_sjNHiLB7O3S3QMM-44a8IdRmKA4Fgmn4YmbXGem_TJd71EIN8gACA0b1qjvBR61SwtmWSYQPoXuxycW3d1DMPQGXlB2tWM0-r5z3t1ExU8anr-k76UHEITUC6Yaco0KfI9ONeijNpjAdEroEKIsB0rCWUC9kQ9GGiaekneXAktdkRsSFu15Wr4L6U1CMPECr_B7lRoUsJAKgU8hGEx9__-c4OsmT00OdOD5g0sSMhl4k3FNiD_uICQk4cwfeNPhc4R823OBUI2WodpKlWgQ_HsfZmpWQi_0_F9jpQ8jPdjwvWB44mJw4mJYceF71KfP8TBLY2BRJFXs1pSE5Ahyo1EdmCk3Ln_2DhZMCCslI791HRj51ccrCpm2J8q2WG-RW6lYOLtHhR58wUQeio8OUrS2LrAnjXx3oJ6FUsTSGsyWaSOOnvNpnhubAakKlPUhxi1PueGFH13eui9T9phC1EFJcf0d-fDIhYCI5RqBgeYJF0xVG9E5MQWS2-J9ltmjRjCP8uzKtQCWHot3X7DhKVPHWgh7VhBv8zbA7RYjU9h72CPkaYxKHK1j5cQk7AgbLL8zKj4tISP_p1cPMvI9WG3h0c5unEdFb5lZgrSb6errEboA9HZewSaC5aZScxmlHeq87lcT2YwTx9sGQe-lMl4VosdHdrTqK7vpp9-BGxtzDDb5DjZY0Hw-28g0F8fass6jPWy5QA8-yEc8oOM1zrGMd8ETbjCGiGVswwU3HHUxnDUmU3GEvczKD7OOMq9Rso1wNlgcW8KAG-8qvg7jaThlV3gdjAcjOqHT8fBqfz0KwvEwHtFxHG5ZMNxiOIziaLuZoE99fzS94tfUp0N_6IfBIBwFQy8cT4ejeDMZbP0BHY6HZOBjwrjwhDgknlS7K651jtdBOBn4gyvBNii0-1KN0jL-KRneXKlr2-HdJt9pMvAF10afTBhuhPu87WzFkOENzPOdBrsKDqiEZG53aIY5sDRu5QZXuRLXe2My7Q7aJaHLHTf7fONFMiF0aUct_3mXKflPjAyhS-eFJnRZOnK4pv8OAAD__3BBJL0">