This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


2673. User-declared spaceship vs. built-in operators

Section: 12.2.2.3  [over.match.oper]     Status: C++23     Submitter: Barry Revzin     Date: 2022-12-30

[Accepted as a DR at the February, 2023 meeting.]

Consider:

  #include <compare>

  enum class E : int {
    Lo = 0,
    Hi = 1
  };

  constexpr auto operator<=>(E lhs, E rhs) -> std::strong_ordering {
    return (int)rhs <=> (int)lhs;
  }

  // everybody agrees this is true
  static_assert((E::Lo <=> E::Hi) == std::strong_ordering::greater);

  // gcc rejects this, msvc and clang accept
  static_assert(E::Lo > E::Hi);  // #1

The intent here is for the user-provided operator<=> to suppress the built-in operator<=> for E. And gcc, clang, and msvc all agree that this does happen when the comparison expression explicitly uses a <=> b.

But when the comparison expression is a @ b for one of the relational operators, gcc disagrees, conforming to 12.2.2.3 [over.match.oper] bullet 3.3:

For all other operators, the built-in candidates include all of the candidate operator functions defined in 12.5 [over.built] that, compared to the given operator, ... do not have the same parameter-type-list as any non-member candidate that is not a function template specialization.

The issue is that, for #1, the user-provided operator<=> is not a non-member candidate, but a rewritten candidate. A similar situation arises for a user-declared operator==, which will be called for e1 == e2, but not for e1 != e2. Again, clang and MSVC disagree.

Proposed resolution (January, 2023) [SUPERSEDED]:

Change 12.2.2.3 [over.match.oper] bullet 3.3.4 as follows:

Proposed resolution (approved by CWG 2023-02-10):

Change 12.2.2.3 [over.match.oper] bullet 3.3.4 as follows: