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