1 // RUN: %check_clang_tidy %s performance-move-const-arg %t 2 3 namespace std { 4 template <typename> 5 struct remove_reference; 6 7 template <typename _Tp> 8 struct remove_reference { 9 typedef _Tp type; 10 }; 11 12 template <typename _Tp> 13 struct remove_reference<_Tp &> { 14 typedef _Tp type; 15 }; 16 17 template <typename _Tp> 18 struct remove_reference<_Tp &&> { 19 typedef _Tp type; 20 }; 21 22 template <typename _Tp> 23 constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) { 24 return static_cast<typename std::remove_reference<_Tp>::type &&>(__t); 25 } 26 27 template <typename _Tp> 28 constexpr _Tp && 29 forward(typename remove_reference<_Tp>::type &__t) noexcept { 30 return static_cast<_Tp &&>(__t); 31 } 32 33 } // namespace std 34 35 class A { 36 public: 37 A() {} 38 A(const A &rhs) {} 39 A(A &&rhs) {} 40 }; 41 42 using AlsoA = A; 43 44 struct TriviallyCopyable { 45 int i; 46 }; 47 48 using TrivialAlias = TriviallyCopyable; 49 50 void f(TriviallyCopyable) {} 51 52 void g() { 53 TriviallyCopyable obj; 54 f(std::move(obj)); 55 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable' has no effect; remove std::move() [performance-move-const-arg] 56 // CHECK-FIXES: f(obj); 57 58 TrivialAlias obj2; 59 f(std::move(obj2)); 60 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: std::move of the variable 'obj2' of the trivially-copyable type 'TrivialAlias' (aka 'TriviallyCopyable') has no effect; remove std::move() [performance-move-const-arg] 61 // CHECK-FIXES: f(obj2); 62 } 63 64 int f1() { 65 return std::move(42); 66 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of the trivially-copyable type 'int' has no effect; remove std::move() [performance-move-const-arg] 67 // CHECK-FIXES: return 42; 68 } 69 70 int f2(int x2) { 71 return std::move(x2); 72 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x2' of the trivially-copyable type 'int' 73 // CHECK-FIXES: return x2; 74 } 75 76 int *f3(int *x3) { 77 return std::move(x3); 78 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x3' of the trivially-copyable type 'int *' 79 // CHECK-FIXES: return x3; 80 } 81 82 A f4(A x4) { return std::move(x4); } 83 84 AlsoA f4_a(AlsoA x4) { return std::move(x4); } 85 86 A f5(const A x5) { 87 return std::move(x5); 88 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x5' has no effect; remove std::move() or make the variable non-const [performance-move-const-arg] 89 // CHECK-FIXES: return x5; 90 } 91 92 AlsoA f5_a(const AlsoA x5) { 93 return std::move(x5); 94 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x5' has no effect; remove std::move() or make the variable non-const [performance-move-const-arg] 95 // CHECK-FIXES: return x5; 96 } 97 98 template <typename T> 99 T f6(const T x6) { 100 return std::move(x6); 101 } 102 103 void f7() { int a = f6(10); } 104 105 #define M1(x) x 106 void f8() { 107 const A a; 108 M1(A b = std::move(a);) 109 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: std::move of the const variable 'a' has no effect; remove std::move() or make the variable non-const 110 // CHECK-FIXES: M1(A b = a;) 111 } 112 113 #define M2(x) std::move(x) 114 int f9() { return M2(1); } 115 116 template <typename T> 117 T f_unknown_target(const int x10) { 118 return std::move(x10); 119 } 120 121 void f11() { 122 f_unknown_target<int>(1); 123 f_unknown_target<double>(1); 124 } 125 126 A&& f_return_right_ref() { 127 static A a{}; 128 return std::move(a); 129 } 130 131 class NoMoveSemantics { 132 public: 133 NoMoveSemantics(); 134 NoMoveSemantics(const NoMoveSemantics &); 135 136 NoMoveSemantics &operator=(const NoMoveSemantics &); 137 }; 138 139 using NoMoveSemanticsAlias = NoMoveSemantics; 140 141 void callByConstRef(const NoMoveSemantics &); 142 void callByConstRef(int i, const NoMoveSemantics &); 143 144 void moveToConstReferencePositives() { 145 NoMoveSemantics obj; 146 147 // Basic case. 148 callByConstRef(std::move(obj)); 149 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as 150 // CHECK-FIXES: callByConstRef(obj); 151 152 // Also works for second argument. 153 callByConstRef(1, std::move(obj)); 154 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as 155 // CHECK-FIXES: callByConstRef(1, obj); 156 157 // Works if std::move() applied to a temporary. 158 callByConstRef(std::move(NoMoveSemantics())); 159 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as 160 // CHECK-FIXES: callByConstRef(NoMoveSemantics()); 161 162 // Works if calling a copy constructor. 163 NoMoveSemantics other(std::move(obj)); 164 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing result of std::move() as 165 // CHECK-FIXES: NoMoveSemantics other(obj); 166 167 // Works if calling assignment operator. 168 other = std::move(obj); 169 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as 170 // CHECK-FIXES: other = obj; 171 } 172 173 void moveToConstReferencePositivesAlias() { 174 NoMoveSemanticsAlias obj; 175 176 // Basic case. 177 callByConstRef(std::move(obj)); 178 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 179 // CHECK-FIXES: callByConstRef(obj); 180 181 // Also works for second argument. 182 callByConstRef(1, std::move(obj)); 183 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 184 // CHECK-FIXES: callByConstRef(1, obj); 185 186 // Works if std::move() applied to a temporary. 187 callByConstRef(std::move(NoMoveSemanticsAlias())); 188 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 189 // CHECK-FIXES: callByConstRef(NoMoveSemanticsAlias()); 190 191 // Works if calling a copy constructor. 192 NoMoveSemanticsAlias other(std::move(obj)); 193 // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 194 // CHECK-FIXES: NoMoveSemanticsAlias other(obj); 195 196 // Works if calling assignment operator. 197 other = std::move(obj); 198 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 199 // CHECK-FIXES: other = obj; 200 } 201 202 class MoveSemantics { 203 public: 204 MoveSemantics(); 205 MoveSemantics(MoveSemantics &&); 206 207 MoveSemantics &operator=(MoveSemantics &&); 208 }; 209 210 using MoveSemanticsAlias = MoveSemantics; 211 212 void callByValue(MoveSemantics); 213 214 void callByRValueRef(MoveSemantics &&); 215 216 template <class T> 217 void templateFunction(T obj) { 218 T other = std::move(obj); 219 } 220 221 #define M3(T, obj) \ 222 do { \ 223 T other = std::move(obj); \ 224 } while (true) 225 226 #define CALL(func) (func)() 227 228 void moveToConstReferenceNegatives() { 229 // No warning when actual move takes place. 230 MoveSemantics move_semantics; 231 callByValue(std::move(move_semantics)); 232 callByRValueRef(std::move(move_semantics)); 233 MoveSemantics other(std::move(move_semantics)); 234 other = std::move(move_semantics); 235 236 // No warning if std::move() not used. 237 NoMoveSemantics no_move_semantics; 238 callByConstRef(no_move_semantics); 239 240 // No warning if instantiating a template. 241 templateFunction(no_move_semantics); 242 243 // No warning inside of macro expansions. 244 M3(NoMoveSemantics, no_move_semantics); 245 246 // No warning inside of macro expansion, even if the macro expansion is inside 247 // a lambda that is, in turn, an argument to a macro. 248 CALL([no_move_semantics] { M3(NoMoveSemantics, no_move_semantics); }); 249 250 auto lambda = [] {}; 251 auto lambda2 = std::move(lambda); 252 } 253 254 void moveToConstReferenceNegativesAlias() { 255 // No warning when actual move takes place. 256 MoveSemanticsAlias move_semantics; 257 callByValue(std::move(move_semantics)); 258 callByRValueRef(std::move(move_semantics)); 259 MoveSemanticsAlias other(std::move(move_semantics)); 260 other = std::move(move_semantics); 261 262 // No warning if std::move() not used. 263 NoMoveSemanticsAlias no_move_semantics; 264 callByConstRef(no_move_semantics); 265 266 // No warning if instantiating a template. 267 templateFunction(no_move_semantics); 268 269 // No warning inside of macro expansions. 270 M3(NoMoveSemanticsAlias, no_move_semantics); 271 272 // No warning inside of macro expansion, even if the macro expansion is inside 273 // a lambda that is, in turn, an argument to a macro. 274 CALL([no_move_semantics] { M3(NoMoveSemanticsAlias, no_move_semantics); }); 275 276 auto lambda = [] {}; 277 auto lambda2 = std::move(lambda); 278 } 279 280 class MoveOnly { 281 public: 282 MoveOnly(const MoveOnly &other) = delete; 283 MoveOnly &operator=(const MoveOnly &other) = delete; 284 MoveOnly(MoveOnly &&other) = default; 285 MoveOnly &operator=(MoveOnly &&other) = default; 286 }; 287 template <class T> 288 void Q(T); 289 void moveOnlyNegatives(MoveOnly val) { 290 Q(std::move(val)); 291 } 292 293 using MoveOnlyAlias = MoveOnly; 294 295 void fmovable(MoveSemantics); 296 297 void lambda1() { 298 auto f = [](MoveSemantics m) { 299 fmovable(std::move(m)); 300 }; 301 f(MoveSemantics()); 302 } 303 304 template<class T> struct function {}; 305 306 template<typename Result, typename... Args> 307 class function<Result(Args...)> { 308 public: 309 function() = default; 310 void operator()(Args... args) const { 311 fmovable(std::forward<Args>(args)...); 312 } 313 }; 314 315 void functionInvocation() { 316 function<void(MoveSemantics)> callback; 317 MoveSemantics m; 318 callback(std::move(m)); 319 } 320 321 void functionInvocationAlias() { 322 function<void(MoveSemanticsAlias)> callback; 323 MoveSemanticsAlias m; 324 callback(std::move(m)); 325 } 326 327 void lambda2() { 328 function<void(MoveSemantics)> callback; 329 330 auto f = [callback = std::move(callback)](MoveSemantics m) mutable { 331 // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: std::move of the variable 'callback' of the trivially-copyable type 'function<void (MoveSemantics)>' has no effect; remove std::move() 332 // CHECK-FIXES: auto f = [callback = callback](MoveSemantics m) mutable { 333 callback(std::move(m)); 334 }; 335 f(MoveSemantics()); 336 } 337 338 void lambda2Alias() { 339 function<void(MoveSemanticsAlias)> callback; 340 341 auto f = [callback = std::move(callback)](MoveSemanticsAlias m) mutable { 342 // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: std::move of the variable 'callback' of the trivially-copyable type 'function<void (MoveSemanticsAlias)>' (aka 'function<void (MoveSemantics)>') has no effect; remove std::move() [performance-move-const-arg] 343 // CHECK-FIXES: auto f = [callback = callback](MoveSemanticsAlias m) mutable { 344 callback(std::move(m)); 345 }; 346 f(MoveSemanticsAlias()); 347 } 348 349 void showInt(int &&v); 350 void showInt(int v1, int &&v2); 351 void showPointer(const char *&&s); 352 void showPointer2(const char *const &&s); 353 void showTriviallyCopyable(TriviallyCopyable &&obj); 354 void showTriviallyCopyablePointer(const TriviallyCopyable *&&obj); 355 void testFunctions() { 356 int a = 10; 357 showInt(std::move(a)); 358 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 359 // CHECK-MESSAGES: :[[@LINE-10]]:20: note: consider changing the 1st parameter of 'showInt' from 'int &&' to 'const int &' 360 showInt(int()); 361 showInt(a, std::move(a)); 362 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 363 // CHECK-MESSAGES: :[[@LINE-13]]:28: note: consider changing the 2nd parameter of 'showInt' from 'int &&' to 'const int &' 364 const char* s = ""; 365 showPointer(std::move(s)); 366 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: std::move of the variable 's' of the trivially-copyable type 'const char *' has no effect [performance-move-const-arg] 367 // CHECK-MESSAGES: :[[@LINE-16]]:32: note: consider changing the 1st parameter of 'showPointer' from 'const char *&&' to 'const char *' 368 showPointer2(std::move(s)); 369 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: std::move of the variable 's' of the trivially-copyable type 'const char *' has no effect [performance-move-const-arg] 370 // CHECK-MESSAGES: :[[@LINE-18]]:39: note: consider changing the 1st parameter of 'showPointer2' from 'const char *const &&' to 'const char *const' 371 TriviallyCopyable *obj = new TriviallyCopyable(); 372 showTriviallyCopyable(std::move(*obj)); 373 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: std::move of the expression of the trivially-copyable type 'TriviallyCopyable' has no effect [performance-move-const-arg] 374 // CHECK-MESSAGES: :[[@LINE-21]]:48: note: consider changing the 1st parameter of 'showTriviallyCopyable' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 375 showTriviallyCopyablePointer(std::move(obj)); 376 // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable *' has no effect [performance-move-const-arg] 377 // CHECK-MESSAGES: :[[@LINE-23]]:62: note: consider changing the 1st parameter of 'showTriviallyCopyablePointer' from 'const TriviallyCopyable *&&' to 'const TriviallyCopyable *' 378 TrivialAlias* obj2 = new TrivialAlias(); 379 showTriviallyCopyable(std::move(*obj)); 380 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: std::move of the expression of the trivially-copyable type 'TriviallyCopyable' has no effect [performance-move-const-arg] 381 // CHECK-MESSAGES: :[[@LINE-28]]:48: note: consider changing the 1st parameter of 'showTriviallyCopyable' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 382 showTriviallyCopyablePointer(std::move(obj)); 383 // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable *' has no effect [performance-move-const-arg] 384 // CHECK-MESSAGES: :[[@LINE-30]]:62: note: consider changing the 1st parameter of 'showTriviallyCopyablePointer' from 'const TriviallyCopyable *&&' to 'const TriviallyCopyable *' 385 } 386 template <class T> 387 void forwardToShowInt(T && t) { 388 showInt(static_cast<T &&>(t)); 389 } 390 void testTemplate() { 391 int a = 10; 392 forwardToShowInt(std::move(a)); 393 // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 394 } 395 396 struct Tmp { 397 Tmp(); 398 Tmp(int &&a); 399 Tmp(int v1, int &&a); 400 Tmp(const char *&&s); 401 Tmp(TriviallyCopyable&& obj); 402 Tmp(const TriviallyCopyable *&&obj); 403 void showTmp(TriviallyCopyable&& t); 404 static void showTmpStatic(TriviallyCopyable&& t); 405 }; 406 using TmpAlias = Tmp; 407 408 void testMethods() { 409 Tmp t; 410 int a = 10; 411 Tmp t1(std::move(a)); 412 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 413 // CHECK-MESSAGES: :[[@LINE-15]]:13: note: consider changing the 1st parameter of 'Tmp' from 'int &&' to 'const int &' 414 Tmp t2(a, std::move(a)); 415 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 416 // CHECK-MESSAGES: :[[@LINE-17]]:21: note: consider changing the 2nd parameter of 'Tmp' from 'int &&' to 'const int &' 417 const char* s = ""; 418 Tmp t3(std::move(s)); 419 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 's' of the trivially-copyable type 'const char *' has no effect [performance-move-const-arg] 420 // CHECK-MESSAGES: :[[@LINE-20]]:21: note: consider changing the 1st parameter of 'Tmp' from 'const char *&&' to 'const char *' 421 TriviallyCopyable *obj = new TriviallyCopyable(); 422 Tmp t4(std::move(*obj)); 423 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of the trivially-copyable type 'TriviallyCopyable' has no effect [performance-move-const-arg] 424 // CHECK-MESSAGES: :[[@LINE-23]]:27: note: consider changing the 1st parameter of 'Tmp' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 425 Tmp t5(std::move(obj)); 426 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable *' has no effect [performance-move-const-arg] 427 // CHECK-MESSAGES: :[[@LINE-25]]:34: note: consider changing the 1st parameter of 'Tmp' from 'const TriviallyCopyable *&&' to 'const TriviallyCopyable *' 428 t.showTmp(std::move(*obj)); 429 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: std::move of the expression of the trivially-copyable type 'TriviallyCopyable' has no effect [performance-move-const-arg] 430 // CHECK-MESSAGES: :[[@LINE-27]]:36: note: consider changing the 1st parameter of 'showTmp' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 431 Tmp::showTmpStatic(std::move(*obj)); 432 // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: std::move of the expression of the trivially-copyable type 'TriviallyCopyable' has no effect [performance-move-const-arg] 433 // CHECK-MESSAGES: :[[@LINE-29]]:49: note: consider changing the 1st parameter of 'showTmpStatic' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 434 } 435 436 void testMethodsAlias() { 437 TmpAlias t; 438 int a = 10; 439 TmpAlias t1(std::move(a)); 440 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 441 // CHECK-MESSAGES: :[[@LINE-43]]:13: note: consider changing the 1st parameter of 'Tmp' from 'int &&' to 'const int &' 442 TmpAlias t2(a, std::move(a)); 443 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 444 // CHECK-MESSAGES: :[[@LINE-45]]:21: note: consider changing the 2nd parameter of 'Tmp' from 'int &&' to 'const int &' 445 const char* s = ""; 446 TmpAlias t3(std::move(s)); 447 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: std::move of the variable 's' of the trivially-copyable type 'const char *' has no effect [performance-move-const-arg] 448 // CHECK-MESSAGES: :[[@LINE-48]]:21: note: consider changing the 1st parameter of 'Tmp' from 'const char *&&' to 'const char *' 449 TrivialAlias *obj = new TrivialAlias(); 450 TmpAlias t4(std::move(*obj)); 451 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: std::move of the expression of the trivially-copyable type 'TrivialAlias' (aka 'TriviallyCopyable') has no effect [performance-move-const-arg] 452 // CHECK-MESSAGES: :[[@LINE-51]]:27: note: consider changing the 1st parameter of 'Tmp' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 453 TmpAlias t5(std::move(obj)); 454 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: std::move of the variable 'obj' of the trivially-copyable type 'TrivialAlias *' (aka 'TriviallyCopyable *') has no effect [performance-move-const-arg] 455 // CHECK-MESSAGES: :[[@LINE-53]]:34: note: consider changing the 1st parameter of 'Tmp' from 'const TriviallyCopyable *&&' to 'const TriviallyCopyable *' 456 t.showTmp(std::move(*obj)); 457 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: std::move of the expression of the trivially-copyable type 'TrivialAlias' (aka 'TriviallyCopyable') has no effect [performance-move-const-arg] 458 // CHECK-MESSAGES: :[[@LINE-55]]:36: note: consider changing the 1st parameter of 'showTmp' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 459 TmpAlias::showTmpStatic(std::move(*obj)); 460 // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: std::move of the expression of the trivially-copyable type 'TrivialAlias' (aka 'TriviallyCopyable') has no effect [performance-move-const-arg] 461 // CHECK-MESSAGES: :[[@LINE-57]]:49: note: consider changing the 1st parameter of 'showTmpStatic' from 'TriviallyCopyable &&' to 'const TriviallyCopyable &' 462 } 463 464 void showA(A &&v) {} 465 void testA() { 466 A a; 467 showA(std::move(a)); 468 } 469 470 void testAAlias() { 471 AlsoA a; 472 showA(std::move(a)); 473 } 474 475 void testFuncPointer() { 476 int a = 10; 477 void (*choice)(int, int &&); 478 choice = showInt; 479 choice(std::move(a), std::move(a)); 480 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect; remove std::move() [performance-move-const-arg] 481 // CHECK-FIXES: choice(a, std::move(a)); 482 // CHECK-MESSAGES: :[[@LINE-3]]:24: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect [performance-move-const-arg] 483 } 484 485 namespace issue_62550 { 486 487 struct NonMoveConstructable { 488 NonMoveConstructable(); 489 NonMoveConstructable(const NonMoveConstructable&); 490 NonMoveConstructable& operator=(const NonMoveConstructable&); 491 NonMoveConstructable& operator=(NonMoveConstructable&&); 492 }; 493 494 void testNonMoveConstructible() { 495 NonMoveConstructable t1; 496 NonMoveConstructable t2{std::move(t1)}; 497 // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 498 // CHECK-MESSAGES: :[[@LINE-11]]:8: note: 'NonMoveConstructable' is not move constructible 499 } 500 501 struct NonMoveAssignable { 502 NonMoveAssignable(); 503 NonMoveAssignable(const NonMoveAssignable&); 504 NonMoveAssignable(NonMoveAssignable&&); 505 506 NonMoveAssignable& operator=(const NonMoveAssignable&); 507 }; 508 509 void testNonMoveAssignable() { 510 NonMoveAssignable t1; 511 NonMoveAssignable t2; 512 513 t2 = std::move(t1); 514 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 515 // CHECK-MESSAGES: :[[@LINE-14]]:8: note: 'NonMoveAssignable' is not move assignable 516 } 517 518 struct NonMoveable { 519 NonMoveable(); 520 NonMoveable(const NonMoveable&); 521 NonMoveable& operator=(const NonMoveable&); 522 }; 523 524 void testNonMoveable() { 525 NonMoveable t1; 526 NonMoveable t2{std::move(t1)}; 527 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 528 // CHECK-MESSAGES: :[[@LINE-10]]:8: note: 'NonMoveable' is not move assignable/constructible 529 530 t1 = std::move(t2); 531 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 532 // CHECK-MESSAGES: :[[@LINE-14]]:8: note: 'NonMoveable' is not move assignable/constructible 533 } 534 535 using AlsoNonMoveable = NonMoveable; 536 537 void testAlsoNonMoveable() { 538 AlsoNonMoveable t1; 539 AlsoNonMoveable t2{std::move(t1)}; 540 // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 541 // CHECK-MESSAGES: :[[@LINE-23]]:8: note: 'NonMoveable' is not move assignable/constructible 542 543 t1 = std::move(t2); 544 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 545 // CHECK-MESSAGES: :[[@LINE-27]]:8: note: 'NonMoveable' is not move assignable/constructible 546 } 547 548 } // namespace issue_62550 549 550 namespace GH111450 { 551 struct Status; 552 553 struct Error { 554 Error(const Status& S); 555 }; 556 557 struct Result { 558 Error E; 559 Result(Status&& S) : E(std::move(S)) {} 560 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg] 561 }; 562 } // namespace GH111450 563