Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CWG2673 [over.match.oper] Spaceship operator doesn't sufficiently suppress builtin-operators #205

Open
brevzin opened this issue Dec 30, 2022 · 1 comment

Comments

@brevzin
Copy link

brevzin commented Dec 30, 2022

Reflector thread: https://lists.isocpp.org/core/2019/10/7407.php

Reference (section label): [over.match.oper]

Issue description:

Consider this example:

#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);

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. The wording in [over.match.oper]/3.3 currently says (emphasis mine):

For all other operators, the built-in candidates include all of the candidate operator functions defined in [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.

When we're evaluating E::Lo > E::Hi, the user-provided operator<=> isn't a non-member candidate, it's a rewritten candidate, so gcc continues to include the built-in. Patrick Palka makes the same argument in a gcc bug opened for this here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200

The same thing happens for operator== vs operator!=. A user-declared operator== will be called for e1 == e2 but not for e1 != e2, the latter is specified to call the built-in per the wording (although clang and msvc don't implement it that way).

Suggested resolution:

This seems like an oversight in the adoption of <=> and the new rewrite rules for ==, where the wording here did not change. Change /3.3.4 to read:

  • do not have the same parameter-type-list as any non-member candidate or rewritten candidate that is not a function template specialization.

clang and msvc already appear to implement it this way.

@jensmaurer jensmaurer changed the title [over.match.oper] Spaceship operator doesn't sufficiently suppress builtin-operators CWG2673 [over.match.oper] Spaceship operator doesn't sufficiently suppress builtin-operators Jan 1, 2023
@jensmaurer
Copy link
Member

CWG2673

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants