bugprone-move-forwarding-reference.cpp
4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// RUN: %check_clang_tidy -std=c++14-or-later %s bugprone-move-forwarding-reference %t -- -- -fno-delayed-template-parsing
namespace std {
template <typename> struct remove_reference;
template <typename _Tp> struct remove_reference { typedef _Tp type; };
template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
template <typename _Tp> struct remove_reference<_Tp &&> { typedef _Tp type; };
template <typename _Tp>
constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
} // namespace std
// Standard case.
template <typename T, typename U> 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<U>(SomeU));
}
// Ignore parentheses around the argument to std::move().
template <typename T, typename U> 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<U>((SomeU)));
}
// Handle the case correctly where std::move() is being used through a using
// declaration.
template <typename T, typename U> 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<U>(SomeU));
}
// Handle the case correctly where a global specifier is prepended to
// std::move().
template <typename T, typename U> 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<U>(SomeU));
}
// Create a correct fix if there are spaces around the scope resolution
// operator.
template <typename T, typename U> 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<U>(SomeU));
}
{
T SomeT(std :: move(SomeU));
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
// CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
}
}
// Ignore const rvalue reference parameters.
template <typename T, typename U> 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 <typename T, typename U> void f7() {
[](U &&SomeU) { T SomeT(std::move(SomeU)); };
}
// Ignore the case where the argument is a lvalue reference.
template <typename T, typename U> 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 <typename T, typename U> 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 <typename T> void foo(T);
void f8() {
A a;
foo<A &&>(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 <typename T, typename U> 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 <typename T, typename U> 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 <typename T, typename U> 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 <typename T> 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<decltype(x)>(x)); }
}