Quuxplusone / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
https://p1144.godbolt.org/z/jf67zx5hq
Other
0 stars 2 forks source link

`__is_trivially_equality_comparable(T)` false positive when the defaulted operator is ineligible #30

Closed Quuxplusone closed 3 months ago

Quuxplusone commented 7 months ago

Clang's __is_trivially_equality_comparable(T) builtin assumes that if a type has any defaulted trivial comparison operator, then all its comparison operators will be tantamount-to-trivial. That's a sane assumption... but only if the defaulted operator is actually eligible for the given T! If the defaulted operator is requires-clause'd away, then we shouldn't consider it relevant to the question of triviality at all. https://godbolt.org/z/3hs4EKPKT

template<bool B>
struct S {
    int i;
    bool operator==(const S&) const requires B = default;
    bool operator==(const S& rhs) const { return (i % 3) == (rhs.i % 3); }
};
static_assert(__is_trivially_equality_comparable(S<true>)); // OK
static_assert(not __is_trivially_equality_comparable(S<false>)); // Oops, this line assert-fails

This compiler misbehavior causes libc++ to miscompile std::equal: https://godbolt.org/z/YPfEG6cv9

    S<false> a[] = {1,2,3};
    S<false> b[] = {4,5,6};
    return std::equal(a, a+3, b, b+3);
      // should be true, not false
Quuxplusone commented 3 months ago

Filed upstream as #89293, fixed in #93113.