Skip to content

Missing suggestion in error message with defaulted three-way comparison when return type is auto #148556

@jonathanpoelen

Description

@jonathanpoelen

When defining a struct that provides at least == and < operators but not a three-way comparison operator, and using auto operator<=>(T const&) = default; in another struct, Clang emits an error indicating that the defaulted operator<=> is implicitly deleted.

<source>:15:12: error: object of type 'Item' cannot be compared because its 'operator<=>' is implicitly deleted
   15 |     Item{} < Item{};
      |            ^
<source>:11:10: note: explicitly defaulted function was implicitly deleted here
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^
<source>:9:7: note: defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for member 'text'
    9 |     A text;
      |       ^

This message is unclear for users who have correctly implemented == and <. GCC, in comparison, provides a much more helpful message suggesting to change the return type from auto to a comparison category type to allow the comparison to use operator< and operator==:

<source>:11:10: note: changing the return type from 'auto' to a comparison category type will allow the comparison to use 'operator<' and 'operator=='
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^~~~~~~~

Desired Behavior

  • Suggest, as GCC does, that changing the return type from auto to a comparison category type (e.g., std::strong_ordering or std::partial_ordering) would allow operator<=> to fall back on operator< and operator==.

Environment

  • Clang version: 17, 18, 19, 20

Code to reproduce

https://godbolt.org/z/6hzfPc7er

#include <compare>

struct A {};

bool operator==(A const&, A const&);
bool operator<(A const&, A const&);

struct Item {
    A text;

    auto operator<=>(const Item &other) const = default;
};

int main() {
    Item{} < Item{};
}

Full Clang Output

<source>:11:10: warning: explicitly defaulted three-way comparison operator is implicitly deleted [-Wdefaulted-function-deleted]
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^
<source>:9:7: note: defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for member 'text'
    9 |     A text;
      |       ^
<source>:11:49: note: replace 'default' with 'delete'
   11 |     auto operator<=>(const Item &other) const = default;
      |                                                 ^~~~~~~
      |                                                 delete
<source>:15:12: error: object of type 'Item' cannot be compared because its 'operator<=>' is implicitly deleted
   15 |     Item{} < Item{};
      |            ^
<source>:11:10: note: explicitly defaulted function was implicitly deleted here
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^
<source>:9:7: note: defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for member 'text'
    9 |     A text;
      |       ^

Full Gcc Output

<source>:15:19: error: use of deleted function 'constexpr auto Item::operator<=>(const Item&) const'
   15 |     Item{} < Item{};
      |                   ^
<source>:11:10: note: 'constexpr auto Item::operator<=>(const Item&) const' is implicitly deleted because the default definition would be ill-formed:
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^~~~~~~~
<source>:9:7: error: no match for 'operator<=>' (operand types are 'A' and 'A')
    9 |     A text;
      |       ^~~~
<source>:11:10: note: changing the return type from 'auto' to a comparison category type will allow the comparison to use 'operator<' and 'operator=='
   11 |     auto operator<=>(const Item &other) const = default;
      |          ^~~~~~~~

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:diagnosticsNew/improved warning or error message in Clang, but not in clang-tidy or static analyzer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions