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 | |
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 { |
118 | static void f() {} |
119 | }; |
120 | |
121 | template <> struct TemplatedType<int> { |
122 | 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 | |
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 | |
200 | OK2(OK2 &&) noexcept(true) {} |
201 | OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; } |
202 | }; |
203 | |
204 | struct OK4 { |
205 | 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 | |
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 | |
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 | |