• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RUN: %clang_cc1 -std=c++2a -verify %s
2 // RUN: %clang_cc1 -std=c++2a -verify %s -DDEFINE_FIRST
3 
4 // As modified by P2002R0:
5 //   The exception specification for a comparison operator function (12.6.2)
6 //   without a noexcept-specifier that is defaulted on its first declaration is
7 //   potentially-throwing if and only if any expression in the implicit
8 //   definition is potentially-throwing.
9 
10 #define CAT2(a, b) a ## b
11 #define CAT(a, b) CAT2(a, b)
12 
13 #ifdef DEFINE_FIRST
14 #define DEF(x) auto CAT(a, __LINE__) = x
15 #else
16 #define DEF(x)
17 #endif
18 
19 namespace std {
20   struct strong_ordering {
21     int n;
22     static const strong_ordering equal, less, greater;
23   };
24   constexpr strong_ordering strong_ordering::equal{0},
25       strong_ordering::less{-1}, strong_ordering::greater{1};
26   bool operator!=(std::strong_ordering o, int n) noexcept;
27 }
28 
29 namespace Eq {
30   struct A {
31     bool operator==(const A&) const = default;
32   };
33   DEF(A() == A());
34   static_assert(noexcept(A() == A()));
35 
36   struct B {
37     bool operator==(const B&) const;
38   };
39   struct C {
40     B b;
41     bool operator==(const C&) const = default;
42   };
43   DEF(C() == C());
44   static_assert(!noexcept(C() == C()));
45 
46   // Ensure we do not trigger odr-use from exception specification computation.
47   template<typename T> struct D {
operator ==Eq::D48     bool operator==(const D &) const {
49       typename T::error error; // expected-error {{no type}}
50     }
51   };
52   struct E {
53     D<E> d;
54     bool operator==(const E&) const = default;
55   };
56   static_assert(!noexcept(E() == E()));
57 
58   // (but we do when defining the function).
59   struct F {
60     D<F> d;
61     bool operator==(const F&) const = default; // expected-note {{in instantiation}}
62   };
63   bool equal = F() == F();
64   static_assert(!noexcept(F() == F()));
65 }
66 
67 namespace Spaceship {
68   struct X {
69     friend std::strong_ordering operator<=>(X, X);
70   };
71   struct Y : X {
72     friend std::strong_ordering operator<=>(Y, Y) = default;
73   };
74   DEF(Y() <=> Y());
75   static_assert(!noexcept(Y() <=> Y()));
76 
77   struct ThrowingCmpCat {
78     ThrowingCmpCat(std::strong_ordering);
79     operator std::strong_ordering();
80   };
81   bool operator!=(ThrowingCmpCat o, int n) noexcept;
82 
83   struct A {
84     friend ThrowingCmpCat operator<=>(A, A) noexcept;
85   };
86 
87   struct B {
88     A a;
89     std::strong_ordering operator<=>(const B&) const = default;
90   };
91   DEF(B() <=> B());
92   static_assert(!noexcept(B() <=> B()));
93 
94   struct C {
95     int n;
96     ThrowingCmpCat operator<=>(const C&) const = default;
97   };
98   DEF(C() <=> C());
99   static_assert(!noexcept(C() <=> C()));
100 
101   struct D {
102     int n;
103     std::strong_ordering operator<=>(const D&) const = default;
104   };
105   DEF(D() <=> D());
106   static_assert(noexcept(D() <=> D()));
107 
108 
109   struct ThrowingCmpCat2 {
110     ThrowingCmpCat2(std::strong_ordering) noexcept;
111     operator std::strong_ordering() noexcept;
112   };
113   bool operator!=(ThrowingCmpCat2 o, int n);
114 
115   struct E {
116     friend ThrowingCmpCat2 operator<=>(E, E) noexcept;
117   };
118 
119   struct F {
120     E e;
121     std::strong_ordering operator<=>(const F&) const = default;
122   };
123   DEF(F() <=> F());
124   static_assert(noexcept(F() <=> F()));
125 
126   struct G {
127     int n;
128     ThrowingCmpCat2 operator<=>(const G&) const = default;
129   };
130   DEF(G() <=> G());
131   static_assert(!noexcept(G() <=> G()));
132 }
133 
134 namespace Synth {
135   struct A {
136     friend bool operator==(A, A) noexcept;
137     friend bool operator<(A, A) noexcept;
138   };
139   struct B {
140     A a;
141     friend std::strong_ordering operator<=>(B, B) = default;
142   };
143   std::strong_ordering operator<=>(B, B) noexcept;
144 
145   struct C {
146     friend bool operator==(C, C);
147     friend bool operator<(C, C) noexcept;
148   };
149   struct D {
150     C c;
151     friend std::strong_ordering operator<=>(D, D) = default; // expected-note {{previous}}
152   };
153   std::strong_ordering operator<=>(D, D) noexcept; // expected-error {{does not match}}
154 
155   struct E {
156     friend bool operator==(E, E) noexcept;
157     friend bool operator<(E, E);
158   };
159   struct F {
160     E e;
161     friend std::strong_ordering operator<=>(F, F) = default; // expected-note {{previous}}
162   };
163   std::strong_ordering operator<=>(F, F) noexcept; // expected-error {{does not match}}
164 }
165 
166 namespace Secondary {
167   struct A {
168     friend bool operator==(A, A);
169     friend bool operator!=(A, A) = default; // expected-note {{previous}}
170 
171     friend int operator<=>(A, A);
172     friend bool operator<(A, A) = default; // expected-note {{previous}}
173     friend bool operator<=(A, A) = default; // expected-note {{previous}}
174     friend bool operator>(A, A) = default; // expected-note {{previous}}
175     friend bool operator>=(A, A) = default; // expected-note {{previous}}
176   };
177   bool operator!=(A, A) noexcept; // expected-error {{does not match}}
178   bool operator<(A, A) noexcept; // expected-error {{does not match}}
179   bool operator<=(A, A) noexcept; // expected-error {{does not match}}
180   bool operator>(A, A) noexcept; // expected-error {{does not match}}
181   bool operator>=(A, A) noexcept; // expected-error {{does not match}}
182 
183   struct B {
184     friend bool operator==(B, B) noexcept;
185     friend bool operator!=(B, B) = default;
186 
187     friend int operator<=>(B, B) noexcept;
188     friend bool operator<(B, B) = default;
189     friend bool operator<=(B, B) = default;
190     friend bool operator>(B, B) = default;
191     friend bool operator>=(B, B) = default;
192   };
193   bool operator!=(B, B) noexcept;
194   bool operator<(B, B) noexcept;
195   bool operator<=(B, B) noexcept;
196   bool operator>(B, B) noexcept;
197   bool operator>=(B, B) noexcept;
198 }
199 
200 // Check that we attempt to define a defaulted comparison before trying to
201 // compute its exception specification.
202 namespace DefineBeforeComputingExceptionSpec {
203   template<int> struct A {
204     A();
205     A(const A&) = delete; // expected-note 3{{here}}
206     friend bool operator==(A, A); // expected-note 3{{passing}}
207     friend bool operator!=(const A&, const A&) = default; // expected-error 3{{call to deleted constructor}}
208   };
209 
210   bool a0 = A<0>() != A<0>(); // expected-note {{in defaulted equality comparison operator}}
211   bool a1 = operator!=(A<1>(), A<1>()); // expected-note {{in defaulted equality comparison operator}}
212 
213   template struct A<2>;
214   bool operator!=(const A<2>&, const A<2>&) noexcept; // expected-note {{in evaluation of exception specification}}
215 
216   template<int> struct B {
217     B();
218     B(const B&) = delete; // expected-note 3{{here}}
219     friend bool operator==(B, B); // expected-note 3{{passing}}
220     bool operator!=(const B&) const = default; // expected-error 3{{call to deleted constructor}}
221   };
222 
223   bool b0 = B<0>() != B<0>(); // expected-note {{in defaulted equality comparison operator}}
224   bool b1 = B<1>().operator!=(B<1>()); // expected-note {{in defaulted equality comparison operator}}
225   int b2 = sizeof(&B<2>::operator!=); // expected-note {{in evaluation of exception specification}}
226 }
227