Issue 148556
Summary Missing suggestion in error message with defaulted three-way comparison when return type is auto
Labels new issue
Assignees
Reporter 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.

```cpp
<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==`:

```cpp
<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

```cpp
#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

```cpp
<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 

```cpp
<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;
      |          ^~~~~~~~
```
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to