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