https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118387

            Bug ID: 118387
           Summary: ICE on spaceship for empty class member: in
                    genericize_spaceship, at cp/method.cc:1101
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: winmikedows at hotmail dot com
  Target Milestone: ---

ICE happened when trying to define an invalid spaceship operator for a class
with an empty class member:
```cpp
#include <compare>

struct B {};

struct A
{
    B b;
    int operator<=>(const A&) const = default;
};

int main()
{
    A a;
    return a <=> a;
}
```
This defaulted spaceship is invalid for two reasons: 1) B does not have any
comparison operator defined, and 2) even if it has, the return type will be
strong_ordering which is not convertible to int.

However, after throwing the usual defaulted as delete error, GCC trunk then
ICEs. Note that ICE does not happen on GCC 14.2, which just exits after
printing the first two error messages.
```
<source>: In function 'int main()':
<source>:14:18: error: use of deleted function 'constexpr int
A::operator<=>(const A&) const'
   14 |     return a <=> a;
      |                  ^
<source>:8:9: note: 'constexpr int A::operator<=>(const A&) const' is
implicitly deleted because the default definition would be ill-formed:
    8 |     int operator<=>(const A&) const = default;
      |         ^~~~~~~~
<source>:7:7: error: no match for 'operator<=>' (operand types are 'B' and 'B')
    7 |     B b;
      |       ^
<source>:8:9: internal compiler error: in genericize_spaceship, at
cp/method.cc:1101
    8 |     int operator<=>(const A&) const = default;
      |         ^~~~~~~~
0x28fe3b5 diagnostic_context::diagnostic_impl(rich_location*,
diagnostic_metadata const*, diagnostic_option_id, char const*, __va_list_tag
(*) [1], diagnostic_t)
        ???:0
0x29151b6 internal_error(char const*, ...)
        ???:0
0xacb842 fancy_abort(char const*, int, char const*)
        ???:0
0xc1df55 build_comparison_op(tree_node*, bool, int)
        ???:0
0xc2679e maybe_explain_implicit_delete(tree_node*)
        ???:0
0xbd0187 mark_used(tree_node*, int)
        ???:0
0xb04e19 build_new_op(op_location_t const&, tree_code, int, tree_node*,
tree_node*, tree_node*, tree_node*, tree_node**, int)
        ???:0
0xda4932 build_x_binary_op(op_location_t const&, tree_code, tree_node*,
tree_code, tree_node*, tree_code, tree_node*, tree_node**, int)
        ???:0
0xce5eba c_parse_file()
        ???:0
0xe45879 c_common_parse_file()
        ???:0
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Compiler returned: 1
```

See https://godbolt.org/z/n83o8TzM4 for a live demonstration.

Also, perhaps a related bug: if you just omit the member b and try to define
`int operator<=>(const A&) const = default;` for an empty struct A, instead of
defaulting as deleted as it should, the program compiles but immediately
crashes when run since the generated <=> body contains an ud2 instruction. This
is not a 15 regression but seems to be a bug that dates back to GCC 10 where
<=> was first supported. See https://godbolt.org/z/T56GacWvv.

Reply via email to