On 1/14/25 4:57 AM, Jakub Jelinek wrote:
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?

OK.

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


Reply via email to