// RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11 -verify %s // RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s // definitions for std::move namespace std { inline namespace foo { template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template typename remove_reference::type &&move(T &&t); } } struct A {}; struct B { B() {} B(A) {} }; A test1(A a1) { A a2; return a1; return a2; return std::move(a1); return std::move(a2); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" } B test2(A a1, B b1) { // Object is different than return type so don't warn. A a2; return a1; return a2; return std::move(a1); return std::move(a2); B b2; return b1; return b2; return std::move(b1); return std::move(b2); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" } A global_a; A test3() { // Don't warn when object is not local. return global_a; return std::move(global_a); static A static_a; return static_a; return std::move(static_a); } A test4() { return A(); return test3(); return std::move(A()); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" return std::move(test3()); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:"" } void test5(A) { test5(A()); test5(test4()); test5(std::move(A())); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" test5(std::move(test4())); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:"" } void test6() { A a1 = A(); A a2 = test3(); A a3 = std::move(A()); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" A a4 = std::move(test3()); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:"" } A test7() { A a1 = std::move(A()); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" A a2 = std::move((A())); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:"" A a3 = (std::move(A())); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:"" A a4 = (std::move((A()))); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:"" return std::move(a1); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" return std::move((a1)); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:"" return (std::move(a1)); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" return (std::move((a1))); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:"" } #define wrap1(x) x #define wrap2(x) x // Macro test. Since the std::move call is outside the macro, it is // safe to suggest a fix-it. A test8() { A a; return std::move(a); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:"" return std::move(wrap1(a)); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:28-[[@LINE-4]]:29}:"" return std::move(wrap1(wrap2(a))); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:35-[[@LINE-4]]:36}:"" } #define test9 \ A test9() { \ A a; \ return std::move(a); \ } // Macro test. The std::call is inside the macro, so no fix-it is suggested. test9 // expected-warning@-1{{prevents copy elision}} // CHECK-NOT: fix-it #define return_a return std::move(a) // Macro test. The std::call is inside the macro, so no fix-it is suggested. A test10() { A a; return_a; // expected-warning@-1{{prevents copy elision}} // CHECK-NOT: fix-it } namespace templates { struct A {}; struct B { B(A); }; // Warn once here since the type is not dependent. template A test1() { A a; return std::move(a); // expected-warning@-1{{prevents copy elision}} // expected-note@-2{{remove std::move call}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:22}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" } void run_test1() { test1(); test1(); } // T1 and T2 may not be the same, the warning may not always apply. template T1 test2() { T2 t; return std::move(t); } void run_test2() { test2(); test2(); } }