xref: /llvm-project/clang/test/CXX/class/class.compare/class.compare.default/p4.cpp (revision d4cf20ca37160cb062a9db773d0e6255d6bbc31a)
1 // RUN: %clang_cc1 -std=c++2a -verify=expected,cxx2a %s
2 // RUN: %clang_cc1 -std=c++23 -verify=expected %s
3 
4 // This test is for [class.compare.default]p3 as modified and renumbered to p4
5 // by P2002R0.
6 // Also covers modifications made by P2448R2
7 
8 namespace std {
9   struct strong_ordering {
10     int n;
operator intstd::strong_ordering11     constexpr operator int() const { return n; }
12     static const strong_ordering less, equal, greater;
13   };
14   constexpr strong_ordering strong_ordering::less = {-1};
15   constexpr strong_ordering strong_ordering::equal = {0};
16   constexpr strong_ordering strong_ordering::greater = {1};
17 }
18 
19 namespace N {
20   struct A {
21     friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default; // expected-note 2{{declared here}}
22   };
23 
24   constexpr std::strong_ordering (*test_a_threeway_not_found)(const A&, const A&) = &operator<=>; // expected-error {{undeclared}}
25 
26   constexpr std::strong_ordering operator<=>(const A&, const A&) noexcept;
27   constexpr std::strong_ordering (*test_a_threeway)(const A&, const A&) = &operator<=>;
28   static_assert(!(*test_a_threeway)(A(), A())); // expected-error {{static assertion expression is not an integral constant expression}}
29                                                // expected-note@-1 {{undefined function 'operator<=>' cannot be used in a constant expression}}
30 
31   constexpr bool (*test_a_equal_not_found)(const A&, const A&) = &operator==; // expected-error {{undeclared}}
32 
33   constexpr bool operator==(const A&, const A&) noexcept;
34   constexpr bool (*test_a_equal)(const A&, const A&) noexcept = &operator==;
35   static_assert((*test_a_equal)(A(), A())); // expected-error {{static assertion expression is not an integral constant expression}}
36                                             // expected-note@-1 {{undefined function 'operator==' cannot be used in a constant expression}}
37 }
38 
39 struct B1 {
40   virtual std::strong_ordering operator<=>(const B1&) const = default;
41 };
42 bool (B1::*test_b)(const B1&) const = &B1::operator==;
43 
44 struct C1 : B1 {
45   // OK, B1::operator== is virtual.
46   bool operator==(const B1&) const override;
47 };
48 
49 struct B2 {
50   std::strong_ordering operator<=>(const B2&) const = default;
51 };
52 
53 struct C2 : B2 {
54   bool operator==(const B2&) const override; // expected-error {{only virtual member functions}}
55 };
56 
57 struct D {
58   std::strong_ordering operator<=>(const D&) const;
59   virtual std::strong_ordering operator<=>(const struct E&) const = 0;
60 };
61 struct E : D {
62   // expected-error@+2 {{only virtual member functions}}
63   // expected-note@+1 {{while declaring the corresponding implicit 'operator==' for this defaulted 'operator<=>'}}
64   std::strong_ordering operator<=>(const E&) const override = default;
65 };
66 
67 struct F {
68   [[deprecated("oh no")]] std::strong_ordering operator<=>(const F&) const = default; // expected-note 4{{deprecated}}
69 };
use_f(F f)70 void use_f(F f) {
71   void(f <=> f); // expected-warning {{oh no}}
72   void(f < f); // expected-warning {{oh no}}
73   void(f == f); // expected-warning {{oh no}}
74   void(f != f); // expected-warning {{oh no}}
75 }
76 
77 class G {
78   // expected-note@+2 {{implicitly declared private here}}
79   // expected-note-re@+1 {{{{^}}declared private here}}
80   std::strong_ordering operator<=>(const G&) const = default;
81 public:
82 };
use_g(G g)83 void use_g(G g) {
84   void(g <=> g); // expected-error {{private}}
85   void(g == g); // expected-error {{private}}
86 }
87 
88 struct H {
89   bool operator==(const H&) const; // cxx2a-note {{non-constexpr comparison function declared here}}
operator <=>H90   constexpr std::strong_ordering operator<=>(const H&) const { return std::strong_ordering::equal; }
91 };
92 
93 struct I {
94   H h; // cxx2a-note {{non-constexpr comparison function would be used to compare member 'h'}}
95   constexpr std::strong_ordering operator<=>(const I&) const = default; // cxx2a-error {{cannot be declared constexpr}}
96 };
97 
98 struct J {
99   std::strong_ordering operator<=>(const J&) const & = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
100   friend std::strong_ordering operator<=>(const J&, const J&) = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
101 };
use_j(J j)102 void use_j(J j) {
103   void(j == j); // expected-error {{ambiguous}}
104 }
105 
106 namespace DeleteAfterFirstDecl {
107   bool operator==(const struct Q&, const struct Q&);
108   struct Q {
109     struct X {
110       friend std::strong_ordering operator<=>(const X&, const X&);
111     } x; // expected-note {{no viable 'operator=='}}
112     // expected-error@+1 {{defaulting the corresponding implicit 'operator==' for this defaulted 'operator<=>' would delete it after its first declaration}}
113     friend std::strong_ordering operator<=>(const Q&, const Q&) = default;
114   };
115 }
116 
117 // Note, substitution here results in the second parameter of 'operator=='
118 // referring to the first parameter of 'operator==', not to the first parameter
119 // of 'operator<=>'.
120 // FIXME: Find a case where this matters (attribute enable_if?).
121 struct K {
122   friend std::strong_ordering operator<=>(const K &k, decltype(k)) = default;
123 };
124 bool test_k = K() == K();
125 
126 namespace NoInjectionIfOperatorEqualsDeclared {
127   struct A {
128     void operator==(int); // expected-note 2{{not viable}}
129     std::strong_ordering operator<=>(const A&) const = default;
130   };
131   bool test_a = A() == A(); // expected-error {{invalid operands}}
132 
133   struct B {
134     friend void operator==(int, struct Q); // expected-note 2{{not viable}}
135     std::strong_ordering operator<=>(const B&) const = default;
136   };
137   bool test_b = B() == B(); // expected-error {{invalid operands}}
138 
139   struct C {
140     void operator==(int); // expected-note 2{{not viable}}
141     friend std::strong_ordering operator<=>(const C&, const C&) = default;
142   };
143   bool test_c = C() == C(); // expected-error {{invalid operands}}
144 
145   struct D {
fNoInjectionIfOperatorEqualsDeclared::D146     void f() {
147       void operator==(const D&, int);
148     }
149     struct X {
150       friend void operator==(const D&, int);
151     };
152     friend std::strong_ordering operator<=>(const D&, const D&) = default;
153   };
154   bool test_d = D() == D();
155 }
156 
157 namespace GH61238 {
158 template <typename A> struct my_struct {
159     A value; // cxx2a-note {{non-constexpr comparison function would be used to compare member 'value'}}
160 
161     constexpr friend bool operator==(const my_struct &, const my_struct &) noexcept = default; // cxx2a-error {{cannot be declared constexpr}}
162 };
163 
164 struct non_constexpr_type {
operator ==(non_constexpr_type,non_constexpr_type)165     friend bool operator==(non_constexpr_type, non_constexpr_type) noexcept { // cxx2a-note {{non-constexpr comparison function declared here}}
166         return false;
167     }
168 };
169 
170 my_struct<non_constexpr_type> obj; // cxx2a-note {{in instantiation of template class 'GH61238::my_struct<GH61238::non_constexpr_type>' requested here}}
171 }
172 
173 namespace Constrained {
174   template<typename T>
175   struct A {
176     std::strong_ordering operator<=>(const A&) const requires true = default;
177   };
178 
f(A<int> a)179   bool f(A<int> a) {
180     return a != A<int>();
181   }
182 }
183