// RUN: %check_clang_tidy %s bugprone-move-forwarding-reference %t -- -- -std=c++14 -fno-delayed-template-parsing namespace std { template struct remove_reference; template struct remove_reference { typedef _Tp type; }; template struct remove_reference<_Tp &> { typedef _Tp type; }; template struct remove_reference<_Tp &&> { typedef _Tp type; }; template constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t); } // namespace std // Standard case. template void f1(U &&SomeU) { T SomeT(std::move(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(std::forward(SomeU)); } // Ignore parentheses around the argument to std::move(). template void f2(U &&SomeU) { T SomeT(std::move((SomeU))); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(std::forward((SomeU))); } // Handle the case correctly where std::move() is being used through a using // declaration. template void f3(U &&SomeU) { using std::move; T SomeT(move(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(std::forward(SomeU)); } // Handle the case correctly where a global specifier is prepended to // std::move(). template void f4(U &&SomeU) { T SomeT(::std::move(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(::std::forward(SomeU)); } // Create a correct fix if there are spaces around the scope resolution // operator. template void f5(U &&SomeU) { { T SomeT(:: std :: move(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(::std::forward(SomeU)); } { T SomeT(std :: move(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to // CHECK-FIXES: T SomeT(std::forward(SomeU)); } } // Ignore const rvalue reference parameters. template void f6(const U &&SomeU) { T SomeT(std::move(SomeU)); } // Ignore the case where the argument to std::move() is a lambda parameter (and // thus not actually a parameter of the function template). template void f7() { [](U &&SomeU) { T SomeT(std::move(SomeU)); }; } // Ignore the case where the argument is a lvalue reference. template void f8(U &SomeU) { T SomeT(std::move(SomeU)); } // Ignore the case where the template parameter is a class template parameter // (i.e. no template argument deduction is taking place). template class SomeClass { void f(U &&SomeU) { T SomeT(std::move(SomeU)); } }; // Ignore the case where the function parameter in the template isn't an rvalue // reference but the template argument is explicitly set to be an rvalue // reference. class A {}; template void foo(T); void f8() { A a; foo(std::move(a)); } // A warning is output, but no fix is suggested, if a macro is used to rename // std::move. #define MOVE(x) std::move((x)) template void f9(U &&SomeU) { T SomeT(MOVE(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to } // Same result if the argument is passed outside of the macro. #undef MOVE #define MOVE std::move template void f10(U &&SomeU) { T SomeT(MOVE(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to } // Same result if the macro does not include the "std" namespace. #undef MOVE #define MOVE move template void f11(U &&SomeU) { T SomeT(std::MOVE(SomeU)); // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to } // Handle the case correctly where the forwarding reference is a parameter of a // generic lambda. template void f12() { [] (auto&& x) { T SomeT(std::move(x)); }; // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); } }