C++20 support in GCC is still experimental, so while it does support the three-way operator, your static_assert is failing because the other compilers are auto inferring the <= operator from the <=> operator, while GCC seems to be more pedantic in its interpretation of the standard, and since you do not have the <= operator directly, the compiler is then emitting a compile time error because it can't find the <= operator.
If you add the <= operator, the code works, example:
struct S{
constexpr operator int() const { return 0; }
constexpr auto operator<=>(S) const { return *this; }
constexpr bool operator<=(S) { return true; }
};
static_assert(S{} <= S{});
Additionally, if you change your assert to be the three way operator, the test fails on all compilers, example:
struct S{
constexpr operator int() const { return 0; }
constexpr auto operator<=>(S) const { return *this; }
};
static_assert(S{} <=> S{});
Furthermore, since the three-way operator is expected to essentially return a negative, zero, or positive value (really returning an ordering), returning *this is likely converting the value to something that Clang and MSVC interpret as a true value for the assert, while GCC could be converting it to a false value, and thus the assert fails.
If you change the return type to any negative value (even -0) or a zero value, the assert passes on all compilers, additionally if you change the value to any positive value above 0 the assert fails on all compilers.
You could change the three-way operator to cast *this to an int which would call operator int and return 0, which would then cause the assert to pass, example:
constexpr auto operator<=>(S) const { return static_cast<int>(*this); }
So to answer directly:
Which compiler is right?
In my experience with GCC, it tends to interpret the language very pedantically and err on the side of caution when it comes to a language specification that might be ambiguous in the face of an odd code snippet (like yours).
To that end, the other compilers might be too loose in their interpretation of the language or GCC might be too strict in this particular case.
Either way, even though this code is "useless," anyone who is running into something like this who is targeting all 3 compilers should probably try to be as pedantic as possible with this type of code, though that might necessarily defeat the purpose of the code in this case, unfortunately.