1 // RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions
2 
3 namespace std
4 {
5   template <typename T>
6   struct is_nothrow_move_constructible
7   {
8     static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T));
9   };
10 } // namespace std
11 
12 struct Empty
13 {};
14 
15 struct IntWrapper {
16   int value;
17 };
18 
19 template <typename T>
20 struct FalseT {
21   static constexpr bool value = false;
22 };
23 
24 template <typename T>
25 struct TrueT {
26   static constexpr bool value = true;
27 };
28 
29 struct ThrowOnAnything {
30   ThrowOnAnything() noexcept(false);
31   ThrowOnAnything(ThrowOnAnything&&) noexcept(false);
32   ThrowOnAnything& operator=(ThrowOnAnything &&) noexcept(false);
33   ~ThrowOnAnything() noexcept(false);
34 };
35 
36 class A {
37   A(A &&);
38   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
39   // CHECK-FIXES: A(A &&) noexcept ;
40   A &operator=(A &&);
41   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
42   // CHECK-FIXES: A &operator=(A &&) noexcept ;
43 };
44 
45 struct B {
46   static constexpr bool kFalse = false;
47   B(B &&) noexcept(kFalse);
48   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
49   B &operator=(B &&) noexcept(kFalse);
50   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
51 };
52 
53 template <typename>
54 struct C {
55   C(C &&);
56   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
57   // CHECK-FIXES: C(C &&) noexcept ;
58   C& operator=(C &&);
59   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
60   // CHECK-FIXES: C& operator=(C &&) noexcept ;
61 };
62 
63 struct D {
64   static constexpr bool kFalse = false;
65   D(D &&) noexcept(kFalse) = default;
66   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
67   D& operator=(D &&) noexcept(kFalse) = default;
68   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
69 };
70 
71 template <typename>
72 struct E {
73   static constexpr bool kFalse = false;
74   E(E &&) noexcept(kFalse);
75   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
76   E& operator=(E &&) noexcept(kFalse);
77   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false'
78 };
79 
80 template <typename>
81 struct F {
82   static constexpr bool kFalse = false;
83   F(F &&) noexcept(kFalse) = default;
84   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
85   F& operator=(F &&) noexcept(kFalse) = default;
86   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
87 };
88 
89 struct G {
90   G(G &&) = default;
91   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
92   // CHECK-FIXES: G(G &&)  noexcept = default;
93   G& operator=(G &&) = default;
94   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
95   // CHECK-FIXES: G& operator=(G &&)  noexcept = default;
96 
97   ThrowOnAnything field;
98 };
99 
throwing_function()100 void throwing_function() noexcept(false) {}
101 
102 struct H {
103   H(H &&) noexcept(noexcept(throwing_function()));
104   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
105   H &operator=(H &&) noexcept(noexcept(throwing_function()));
106   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
107 };
108 
109 template <typename>
110 struct I {
111   I(I &&) noexcept(noexcept(throwing_function()));
112   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
113   I &operator=(I &&) noexcept(noexcept(throwing_function()));
114   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
115 };
116 
117 template <typename T> struct TemplatedType {
fTemplatedType118   static void f() {}
119 };
120 
121 template <> struct TemplatedType<int> {
fTemplatedType122   static void f() noexcept {}
123 };
124 
125 struct J {
126   J(J &&) noexcept(noexcept(TemplatedType<double>::f()));
127   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
128   J &operator=(J &&) noexcept(noexcept(TemplatedType<double>::f()));
129   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
130 };
131 
132 struct K : public ThrowOnAnything {
133   K(K &&) = default;
134   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
135   // CHECK-FIXES: K(K &&)  noexcept = default;
136   K &operator=(K &&) = default;
137   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
138   // CHECK-FIXES: K &operator=(K &&)  noexcept = default;
139 };
140 
141 struct InheritFromThrowOnAnything : public ThrowOnAnything
142 {};
143 
144 struct L {
145   L(L &&) = default;
146   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
147   // CHECK-FIXES: L(L &&)  noexcept = default;
148   L &operator=(L &&) = default;
149   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
150   // CHECK-FIXES: L &operator=(L &&)  noexcept = default;
151 
152   InheritFromThrowOnAnything IFF;
153 };
154 
155 struct M : public InheritFromThrowOnAnything {
156   M(M &&) = default;
157   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
158   // CHECK-FIXES: M(M &&)  noexcept = default;
159   M &operator=(M &&) = default;
160   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
161   // CHECK-FIXES: M &operator=(M &&)  noexcept = default;
162 };
163 
164 struct N : public IntWrapper, ThrowOnAnything {
165   N(N &&) = default;
166   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
167   // CHECK-FIXES: N(N &&)  noexcept = default;
168   N &operator=(N &&) = default;
169   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
170   // CHECK-FIXES: N &operator=(N &&)  noexcept = default;
171 };
172 
173 struct O : virtual IntWrapper, ThrowOnAnything {
174   O(O &&) = default;
175   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
176   // CHECK-FIXES: O(O &&)  noexcept = default;
177   O &operator=(O &&) = default;
178   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
179   // CHECK-FIXES: O &operator=(O &&)  noexcept = default;
180 };
181 
182 class OK {};
183 
f()184 void f() {
185   OK a;
186   a = OK();
187 }
188 
189 struct OK1 {
190   OK1(const OK1 &);
191   OK1(OK1 &&) noexcept;
192   OK1 &operator=(OK1 &&) noexcept;
193   void f();
194   void g() noexcept;
195 };
196 
197 struct OK2 {
198   static constexpr bool kTrue = true;
199 
OK2OK2200   OK2(OK2 &&) noexcept(true) {}
operator =OK2201   OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
202 };
203 
204 struct OK4 {
OK4OK4205   OK4(OK4 &&) noexcept(false) {}
206   OK4 &operator=(OK4 &&) = delete;
207 };
208 
209 struct OK3 {
210   OK3(OK3 &&) noexcept = default;
211   OK3 &operator=(OK3 &&) noexcept = default;
212 };
213 
214 struct OK5 {
215   OK5(OK5 &&) noexcept(true) = default;
216   OK5 &operator=(OK5 &&) noexcept(true) = default;
217 };
218 
219 struct OK6 {
220   OK6(OK6 &&) = default;
221   OK6& operator=(OK6 &&) = default;
222 };
223 
224 template <typename>
225 struct OK7 {
226   OK7(OK7 &&) = default;
227   OK7& operator=(OK7 &&) = default;
228 };
229 
230 template <typename>
231 struct OK8 {
232   OK8(OK8 &&) noexcept = default;
233   OK8& operator=(OK8 &&) noexcept = default;
234 };
235 
236 template <typename>
237 struct OK9 {
238   OK9(OK9 &&) noexcept(true) = default;
239   OK9& operator=(OK9 &&) noexcept(true) = default;
240 };
241 
242 template <typename>
243 struct OK10 {
244   OK10(OK10 &&) noexcept(false) = default;
245   OK10& operator=(OK10 &&) noexcept(false) = default;
246 };
247 
248 template <typename>
249 struct OK11 {
250   OK11(OK11 &&) = delete;
251   OK11& operator=(OK11 &&) = delete;
252 };
253 
noexcept_function()254 void noexcept_function() noexcept {}
255 
256 struct OK12 {
257   OK12(OK12 &&) noexcept(noexcept(noexcept_function()));
258   OK12 &operator=(OK12 &&) noexcept(noexcept(noexcept_function));
259 };
260 
261 struct OK13 {
262   OK13(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
263   OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
264 };
265 
266 template <typename>
267 struct OK14 {
268   OK14(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
269   OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
270 };
271 
272 struct OK15 {
273   OK15(OK15 &&) = default;
274   OK15 &operator=(OK15 &&) = default;
275 
276   int member;
277 };
278 
279 template <typename>
280 struct OK16 {
281   OK16(OK16 &&) = default;
282   OK16 &operator=(OK16 &&) = default;
283 
284   int member;
285 };
286 
287 struct OK17 {
288   OK17(OK17 &&) = default;
289   OK17 &operator=(OK17 &&) = default;
290 
291   OK empty_field;
292 };
293 
294 template <typename>
295 struct OK18 {
296   OK18(OK18 &&) = default;
297   OK18 &operator=(OK18 &&) = default;
298 
299   OK empty_field;
300 };
301 
302 struct OK19 : public OK {
303   OK19(OK19 &&) = default;
304   OK19 &operator=(OK19 &&) = default;
305 };
306 
307 struct OK20 : virtual OK {
308   OK20(OK20 &&) = default;
309   OK20 &operator=(OK20 &&) = default;
310 };
311 
312 template <typename T>
313 struct OK21 : public T {
314   OK21() = default;
315   OK21(OK21 &&) = default;
316   OK21 &operator=(OK21 &&) = default;
317 };
318 
319 template <typename T>
320 struct OK22 : virtual T {
321   OK22() = default;
322   OK22(OK22 &&) = default;
323   OK22 &operator=(OK22 &&) = default;
324 };
325 
326 template <typename T>
327 struct OK23 {
328   OK23() = default;
329   OK23(OK23 &&) = default;
330   OK23 &operator=(OK23 &&) = default;
331 
332   T member;
333 };
334 
testTemplates()335 void testTemplates() {
336   OK21<Empty> value(OK21<Empty>{});
337   value = OK21<Empty>{};
338 
339   OK22<Empty> value2{OK22<Empty>{}};
340   value2 = OK22<Empty>{};
341 
342   OK23<Empty> value3{OK23<Empty>{}};
343   value3 =OK23<Empty>{};
344 }
345 
346 struct OK24 : public Empty, OK1 {
347   OK24(OK24 &&) = default;
348   OK24 &operator=(OK24 &&) = default;
349 };
350 
351 struct OK25 : virtual Empty, OK1 {
352   OK25(OK25 &&) = default;
353   OK25 &operator=(OK25 &&) = default;
354 };
355 
356 struct OK26 : public Empty, IntWrapper {
357   OK26(OK26 &&) = default;
358   OK26 &operator=(OK26 &&) = default;
359 };
360 
361 template <typename T>
362 struct OK27 : public T {
363   OK27(OK27 &&) = default;
364   OK27 &operator=(OK27 &&) = default;
365 };
366 
367 template <typename T>
368 struct OK28 : virtual T {
369   OK28(OK28 &&) = default;
370   OK28 &operator=(OK28 &&) = default;
371 };
372 
373 template <typename T>
374 struct OK29 {
375   OK29(OK29 &&) = default;
376   OK29 &operator=(OK29 &&) = default;
377 
378   T member;
379 };
380 
381 struct OK30 {
382   OK30(OK30 &&) noexcept(TrueT<OK30>::value) = default;
383   OK30& operator=(OK30 &&) noexcept(TrueT<OK30>::value) = default;
384 };
385 
386 template <typename>
387 struct OK31 {
388   OK31(OK31 &&) noexcept(TrueT<int>::value) = default;
389   OK31& operator=(OK31 &&) noexcept(TrueT<int>::value) = default;
390 };
391 
392 namespace gh68101
393 {
394   template <typename T>
395   class Container {
396      public:
397       Container(Container&&) noexcept(std::is_nothrow_move_constructible<T>::value);
398   };
399 } // namespace gh68101
400