On Mon, Jan 13, 2025 at 08:35:57PM -0500, Jason Merrill wrote: > I'd rather hoist the build_static_cast from later; the rules for static cast > aren't quite the same as can_convert. See: > > > if (defining) > > { > > tree val; > > if (code == EQ_EXPR) > > val = boolean_true_node; > > else > > { > > tree seql = lookup_comparison_result (cc_strong_ordering, > > "equal", complain); > > val = build_static_cast (input_location, rettype, seql, > > complain); > > Apparently this also needs to happen when !defining.
Ok, so like this then? 2025-01-14 Jakub Jelinek <ja...@redhat.com> PR c++/118387 * method.cc (build_comparison_op): Set bad if std::strong_ordering::equal doesn't convert to rettype. * g++.dg/cpp2a/spaceship-err6.C: Expect another error. * g++.dg/cpp2a/spaceship-synth17.C: Likewise. * g++.dg/cpp2a/spaceship-synth-neg6.C: Likewise. * g++.dg/cpp2a/spaceship-synth-neg7.C: New test. * testsuite/25_algorithms/default_template_value.cc (Input::operator<=>): Use auto as return type rather than bool. --- gcc/cp/method.cc.jj 2025-01-11 21:58:05.387588681 +0100 +++ gcc/cp/method.cc 2025-01-14 09:45:14.064303749 +0100 @@ -1635,6 +1635,18 @@ build_comparison_op (tree fndecl, bool d rettype = common_comparison_type (comps); apply_deduced_return_type (fndecl, rettype); } + tree retvaleq; + if (code == EQ_EXPR) + retvaleq = boolean_true_node; + else + { + tree seql = lookup_comparison_result (cc_strong_ordering, + "equal", complain); + retvaleq = build_static_cast (input_location, rettype, seql, + complain); + if (retvaleq == error_mark_node) + bad = true; + } if (bad) { DECL_DELETED_FN (fndecl) = true; @@ -1722,19 +1734,7 @@ build_comparison_op (tree fndecl, bool d } } if (defining) - { - tree val; - if (code == EQ_EXPR) - val = boolean_true_node; - else - { - tree seql = lookup_comparison_result (cc_strong_ordering, - "equal", complain); - val = build_static_cast (input_location, rettype, seql, - complain); - } - finish_return_stmt (val); - } + finish_return_stmt (retvaleq); } else if (code == NE_EXPR) { --- gcc/testsuite/g++.dg/cpp2a/spaceship-err6.C.jj 2021-04-14 19:19:14.050804249 +0200 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-err6.C 2025-01-14 10:27:12.311540443 +0100 @@ -10,7 +10,7 @@ class MyClass public: MyClass(int value): mValue(value) {} - bool operator<=>(const MyClass&) const = default; + bool operator<=>(const MyClass&) const = default; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'bool'" } }; int main() --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth17.C.jj 2025-01-11 21:58:05.460587663 +0100 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth17.C 2025-01-14 10:32:00.246561725 +0100 @@ -8,7 +8,7 @@ struct B {}; struct A { B b; // { dg-error "no match for 'operator<=>' in '\[^\n\r]*' \\\(operand types are 'B' and 'B'\\\)" } - int operator<=> (const A &) const = default; + int operator<=> (const A &) const = default; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'int'" } }; int --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C.jj 2021-08-12 20:37:12.696473756 +0200 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C 2025-01-14 10:27:49.739023268 +0100 @@ -5,7 +5,7 @@ struct S { int a; // { dg-error "three-way comparison of 'S::a' has type 'std::strong_ordering', which does not convert to 'int\\*'" } - int *operator<=>(const S&) const = default; + int *operator<=>(const S&) const = default; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'int\\*'" } }; bool b = S{} < S{}; // { dg-error "use of deleted function 'constexpr int\\* S::operator<=>\\\(const S&\\\) const'" } --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg7.C.jj 2025-01-13 16:19:09.897650742 +0100 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg7.C 2025-01-14 10:31:31.802954766 +0100 @@ -0,0 +1,58 @@ +// PR c++/118387 +// { dg-do compile { target c++20 } } + +#include <compare> + +struct A { + int operator<=> (const A &) const; +}; + +struct B { + A a; + int operator<=> (const B &) const = default; // { dg-message "'constexpr int B::operator<=>\\\(const B&\\\) const' is implicitly deleted because the default definition would be ill-formed:" } +}; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'int'" "" { target *-*-* } .-1 } + +struct C { + int operator<=> (const C &) const = default; // { dg-message "'constexpr int C::operator<=>\\\(const C&\\\) const' is implicitly deleted because the default definition would be ill-formed:" } +}; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'int'" "" { target *-*-* } .-1 } + +struct D { + auto operator<=> (const D &) const = default; +}; + +struct E { + D a; // { dg-error "three-way comparison of 'E::a' has type 'std::strong_ordering', which does not convert to 'int'" } + int operator<=> (const E &) const = default; // { dg-message "'constexpr int E::operator<=>\\\(const E&\\\) const' is implicitly deleted because the default definition would be ill-formed:" } +}; // { dg-error "invalid 'static_cast' from type 'const std::strong_ordering' to type 'int'" "" { target *-*-* } .-1 } + +struct F { + A a; + int operator<=> (const F &) const = default; +}; + +struct G { + int operator<=> (const G &) const = default; +}; + +struct H { + D a; + int operator<=> (const H &) const = default; +}; + +auto +foo (B a, B b) +{ + return a <=> b; // { dg-error "use of deleted function 'constexpr int B::operator<=>\\\(const B&\\\) const'" } +} + +auto +bar (C a, C b) +{ + return a <=> b; // { dg-error "use of deleted function 'constexpr int C::operator<=>\\\(const C&\\\) const'" } +} + +auto +baz (E a, E b) +{ + return a <=> b; // { dg-error "use of deleted function 'constexpr int E::operator<=>\\\(const E&\\\) const'" } +} --- libstdc++-v3/testsuite/25_algorithms/default_template_value.cc.jj 2024-09-24 15:14:54.199160911 +0200 +++ libstdc++-v3/testsuite/25_algorithms/default_template_value.cc 2025-01-14 10:40:02.304872699 +0100 @@ -27,7 +27,7 @@ struct Output struct Input { Input(int, double); - friend bool operator<=>(const Input &, const Input &) = default; + friend auto operator<=>(const Input &, const Input &) = default; friend Input operator+(const Input &, const Input &); operator Output() const; }; Jakub