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()100void 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()184void 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()254void 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()335void 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