1*89a1d03eSRichard // RUN: %check_clang_tidy -std=c++14-or-later %s bugprone-move-forwarding-reference %t -- -- -fno-delayed-template-parsing
2*89a1d03eSRichard
3*89a1d03eSRichard namespace std {
4*89a1d03eSRichard template <typename> struct remove_reference;
5*89a1d03eSRichard
6*89a1d03eSRichard template <typename _Tp> struct remove_reference { typedef _Tp type; };
7*89a1d03eSRichard
8*89a1d03eSRichard template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
9*89a1d03eSRichard
10*89a1d03eSRichard template <typename _Tp> struct remove_reference<_Tp &&> { typedef _Tp type; };
11*89a1d03eSRichard
12*89a1d03eSRichard template <typename _Tp>
13*89a1d03eSRichard constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
14*89a1d03eSRichard
15*89a1d03eSRichard } // namespace std
16*89a1d03eSRichard
17*89a1d03eSRichard // Standard case.
f1(U && SomeU)18*89a1d03eSRichard template <typename T, typename U> void f1(U &&SomeU) {
19*89a1d03eSRichard T SomeT(std::move(SomeU));
20*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
21*89a1d03eSRichard // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
22*89a1d03eSRichard }
23*89a1d03eSRichard
24*89a1d03eSRichard // Ignore parentheses around the argument to std::move().
f2(U && SomeU)25*89a1d03eSRichard template <typename T, typename U> void f2(U &&SomeU) {
26*89a1d03eSRichard T SomeT(std::move((SomeU)));
27*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
28*89a1d03eSRichard // CHECK-FIXES: T SomeT(std::forward<U>((SomeU)));
29*89a1d03eSRichard }
30*89a1d03eSRichard
31*89a1d03eSRichard // Handle the case correctly where std::move() is being used through a using
32*89a1d03eSRichard // declaration.
f3(U && SomeU)33*89a1d03eSRichard template <typename T, typename U> void f3(U &&SomeU) {
34*89a1d03eSRichard using std::move;
35*89a1d03eSRichard T SomeT(move(SomeU));
36*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
37*89a1d03eSRichard // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
38*89a1d03eSRichard }
39*89a1d03eSRichard
40*89a1d03eSRichard // Handle the case correctly where a global specifier is prepended to
41*89a1d03eSRichard // std::move().
f4(U && SomeU)42*89a1d03eSRichard template <typename T, typename U> void f4(U &&SomeU) {
43*89a1d03eSRichard T SomeT(::std::move(SomeU));
44*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
45*89a1d03eSRichard // CHECK-FIXES: T SomeT(::std::forward<U>(SomeU));
46*89a1d03eSRichard }
47*89a1d03eSRichard
48*89a1d03eSRichard // Create a correct fix if there are spaces around the scope resolution
49*89a1d03eSRichard // operator.
f5(U && SomeU)50*89a1d03eSRichard template <typename T, typename U> void f5(U &&SomeU) {
51*89a1d03eSRichard {
52*89a1d03eSRichard T SomeT(:: std :: move(SomeU));
53*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
54*89a1d03eSRichard // CHECK-FIXES: T SomeT(::std::forward<U>(SomeU));
55*89a1d03eSRichard }
56*89a1d03eSRichard {
57*89a1d03eSRichard T SomeT(std :: move(SomeU));
58*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
59*89a1d03eSRichard // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
60*89a1d03eSRichard }
61*89a1d03eSRichard }
62*89a1d03eSRichard
63*89a1d03eSRichard // Ignore const rvalue reference parameters.
f6(const U && SomeU)64*89a1d03eSRichard template <typename T, typename U> void f6(const U &&SomeU) {
65*89a1d03eSRichard T SomeT(std::move(SomeU));
66*89a1d03eSRichard }
67*89a1d03eSRichard
68*89a1d03eSRichard // Ignore the case where the argument to std::move() is a lambda parameter (and
69*89a1d03eSRichard // thus not actually a parameter of the function template).
f7()70*89a1d03eSRichard template <typename T, typename U> void f7() {
71*89a1d03eSRichard [](U &&SomeU) { T SomeT(std::move(SomeU)); };
72*89a1d03eSRichard }
73*89a1d03eSRichard
74*89a1d03eSRichard // Ignore the case where the argument is a lvalue reference.
f8(U & SomeU)75*89a1d03eSRichard template <typename T, typename U> void f8(U &SomeU) {
76*89a1d03eSRichard T SomeT(std::move(SomeU));
77*89a1d03eSRichard }
78*89a1d03eSRichard
79*89a1d03eSRichard // Ignore the case where the template parameter is a class template parameter
80*89a1d03eSRichard // (i.e. no template argument deduction is taking place).
81*89a1d03eSRichard template <typename T, typename U> class SomeClass {
f(U && SomeU)82*89a1d03eSRichard void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
83*89a1d03eSRichard };
84*89a1d03eSRichard
85*89a1d03eSRichard // Ignore the case where the function parameter in the template isn't an rvalue
86*89a1d03eSRichard // reference but the template argument is explicitly set to be an rvalue
87*89a1d03eSRichard // reference.
88*89a1d03eSRichard class A {};
89*89a1d03eSRichard template <typename T> void foo(T);
f8()90*89a1d03eSRichard void f8() {
91*89a1d03eSRichard A a;
92*89a1d03eSRichard foo<A &&>(std::move(a));
93*89a1d03eSRichard }
94*89a1d03eSRichard
95*89a1d03eSRichard // A warning is output, but no fix is suggested, if a macro is used to rename
96*89a1d03eSRichard // std::move.
97*89a1d03eSRichard #define MOVE(x) std::move((x))
f9(U && SomeU)98*89a1d03eSRichard template <typename T, typename U> void f9(U &&SomeU) {
99*89a1d03eSRichard T SomeT(MOVE(SomeU));
100*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
101*89a1d03eSRichard }
102*89a1d03eSRichard
103*89a1d03eSRichard // Same result if the argument is passed outside of the macro.
104*89a1d03eSRichard #undef MOVE
105*89a1d03eSRichard #define MOVE std::move
f10(U && SomeU)106*89a1d03eSRichard template <typename T, typename U> void f10(U &&SomeU) {
107*89a1d03eSRichard T SomeT(MOVE(SomeU));
108*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
109*89a1d03eSRichard }
110*89a1d03eSRichard
111*89a1d03eSRichard // Same result if the macro does not include the "std" namespace.
112*89a1d03eSRichard #undef MOVE
113*89a1d03eSRichard #define MOVE move
f11(U && SomeU)114*89a1d03eSRichard template <typename T, typename U> void f11(U &&SomeU) {
115*89a1d03eSRichard T SomeT(std::MOVE(SomeU));
116*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
117*89a1d03eSRichard }
118*89a1d03eSRichard
119*89a1d03eSRichard // Handle the case correctly where the forwarding reference is a parameter of a
120*89a1d03eSRichard // generic lambda.
f12()121*89a1d03eSRichard template <typename T> void f12() {
122*89a1d03eSRichard [] (auto&& x) { T SomeT(std::move(x)); };
123*89a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
124*89a1d03eSRichard // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward<decltype(x)>(x)); }
125*89a1d03eSRichard }
126