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