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. |
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(). |
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. |
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(). |
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. |
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. |
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). |
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. |
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 { |
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 (T); |
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)) |
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 |
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 |
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. |
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 | |