1// RUN: %check_clang_tidy -std=c++14-or-later %s bugprone-move-forwarding-reference %t -- -- -fno-delayed-template-parsing
2
3namespace std {
4template <typename> struct remove_reference;
5
6template <typename _Tp> struct remove_reference { typedef _Tp type; };
7
8template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
9
10template <typename _Tp> struct remove_reference<_Tp &&> { typedef _Tp type; };
11
12template <typename _Tp>
13constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
14
15} // namespace std
16
17// Standard case.
18template <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().
25template <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.
33template <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().
42template <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.
50template <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.
64template <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).
70template <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.
75template <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).
81template <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.
88class A {};
89template <typename T> void foo(T);
90void 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))
98template <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
106template <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
114template <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.
121template <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

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/move-forwarding-reference.cpp