1 // RUN: %check_clang_tidy -std=c++11 %s cppcoreguidelines-rvalue-reference-param-not-moved %t -- \
2 // RUN: -config="{CheckOptions: {cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreNonDeducedTemplateTypes: true}}" -- -fno-delayed-template-parsing
3 // RUN: %check_clang_tidy -check-suffix=,CXX14 -std=c++14 %s cppcoreguidelines-rvalue-reference-param-not-moved %t -- \
4 // RUN: -config="{CheckOptions: {cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreNonDeducedTemplateTypes: true}}" -- -fno-delayed-template-parsing
5 // RUN: %check_clang_tidy -check-suffix=,NOSUBEXPR -std=c++11 %s cppcoreguidelines-rvalue-reference-param-not-moved %t -- \
6 // RUN: -config="{CheckOptions: {cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: false, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreNonDeducedTemplateTypes: true}}" -- -fno-delayed-template-parsing
7 // RUN: %check_clang_tidy -check-suffix=,UNNAMED -std=c++11 %s cppcoreguidelines-rvalue-reference-param-not-moved %t -- \
8 // RUN: -config="{CheckOptions: {cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams: false, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreNonDeducedTemplateTypes: true}}" -- -fno-delayed-template-parsing
9 // RUN: %check_clang_tidy -check-suffix=,NONDEDUCED -std=c++11 %s cppcoreguidelines-rvalue-reference-param-not-moved %t -- \
10 // RUN: -config="{CheckOptions: {cppcoreguidelines-rvalue-reference-param-not-moved.AllowPartialMove: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams: true, cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreNonDeducedTemplateTypes: false}}" -- -fno-delayed-template-parsing
11 
12 // NOLINTBEGIN
13 namespace std {
14 template <typename>
15 struct remove_reference;
16 
17 template <typename _Tp> struct remove_reference { typedef _Tp type; };
18 template <typename _Tp> struct remove_reference<_Tp&> { typedef _Tp type; };
19 template <typename _Tp> struct remove_reference<_Tp&&> { typedef _Tp type; };
20 
21 template <typename _Tp>
22 constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept;
23 
24 template <typename _Tp>
25 constexpr _Tp &&
26 forward(typename remove_reference<_Tp>::type &__t) noexcept;
27 
28 }
29 // NOLINTEND
30 
31 struct Obj {
32   Obj();
33   Obj(const Obj&);
34   Obj& operator=(const Obj&);
35   Obj(Obj&&);
36   Obj& operator=(Obj&&);
37   void member() const;
38 };
39 
40 void consumes_object(Obj);
41 
never_moves_param(Obj && o)42 void never_moves_param(Obj&& o) {
43   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
44   o.member();
45 }
46 
47 void just_a_declaration(Obj&& o);
48 
copies_object(Obj && o)49 void copies_object(Obj&& o) {
50   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
51   Obj copy = o;
52 }
53 
54 template <typename T>
never_moves_param_template(Obj && o,T t)55 void never_moves_param_template(Obj&& o, T t) {
56   // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
57   o.member();
58 }
59 
never_moves_params(Obj && o1,Obj && o2)60 void never_moves_params(Obj&& o1, Obj&& o2) {
61   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: rvalue reference parameter 'o1' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
62   // CHECK-MESSAGES: :[[@LINE-2]]:41: warning: rvalue reference parameter 'o2' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
63 }
64 
never_moves_some_params(Obj && o1,Obj && o2)65 void never_moves_some_params(Obj&& o1, Obj&& o2) {
66   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: rvalue reference parameter 'o1' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
67 
68   Obj other{std::move(o2)};
69 }
70 
never_moves_unnamed(Obj &&)71 void never_moves_unnamed(Obj&&) {}
72 // CHECK-MESSAGES-UNNAMED: :[[@LINE-1]]:31: warning: rvalue reference parameter '' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
73 
never_moves_mixed(Obj o1,Obj && o2)74 void never_moves_mixed(Obj o1, Obj&& o2) {
75   // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: rvalue reference parameter 'o2' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
76 }
77 
lambda_captures_parameter_as_value(Obj && o)78 void lambda_captures_parameter_as_value(Obj&& o) {
79   auto f = [o]() {
80     consumes_object(std::move(o));
81   };
82   // CHECK-MESSAGES: :[[@LINE-4]]:47: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
83 }
84 
lambda_captures_parameter_as_value_nested(Obj && o)85 void lambda_captures_parameter_as_value_nested(Obj&& o) {
86   // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
87   auto f = [&o]() {
88     auto f_nested = [o]() {
89       consumes_object(std::move(o));
90     };
91   };
92   auto f2 = [o]() {
93     auto f_nested = [&o]() {
94       consumes_object(std::move(o));
95     };
96   };
97   auto f3 = [o]() {
98     auto f_nested = [&o]() {
99       auto f_nested_inner = [&o]() {
100         consumes_object(std::move(o));
101       };
102     };
103   };
104   auto f4 = [&o]() {
105     auto f_nested = [&o]() {
106       auto f_nested_inner = [o]() {
107         consumes_object(std::move(o));
108       };
109     };
110   };
111 }
112 
misc_lambda_checks()113 void misc_lambda_checks() {
114   auto never_moves = [](Obj&& o1) {
115     Obj other{o1};
116   };
117   // CHECK-MESSAGES: :[[@LINE-3]]:31: warning: rvalue reference parameter 'o1' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
118 
119 #if __cplusplus >= 201402L
120   auto never_moves_with_auto_param = [](Obj&& o1, auto& v) {
121     Obj other{o1};
122   };
123   // CHECK-MESSAGES-CXX14: :[[@LINE-3]]:47: warning: rvalue reference parameter 'o1' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
124 #endif
125 }
126 
127 template <typename T>
forwarding_ref(T && t)128 void forwarding_ref(T&& t) {
129   t.member();
130 }
131 
132 template <typename T>
forwarding_ref_forwarded(T && t)133 void forwarding_ref_forwarded(T&& t) {
134   forwarding_ref(std::forward<T>(t));
135 }
136 
137 template <typename... Ts>
type_pack(Ts &&...ts)138 void type_pack(Ts&&... ts) {
139   (forwarding_ref(std::forward<Ts>(ts)), ...);
140 }
141 
call_forwarding_functions()142 void call_forwarding_functions() {
143   Obj o;
144 
145   forwarding_ref(Obj{});
146   type_pack(Obj{});
147   type_pack(Obj{}, o);
148   type_pack(Obj{}, Obj{});
149 }
150 
moves_parameter(Obj && o)151 void moves_parameter(Obj&& o) {
152   Obj moved = std::move(o);
153 }
154 
moves_parameter_extra_parens(Obj && o)155 void moves_parameter_extra_parens(Obj&& o) {
156   Obj moved = std::move((o));
157 }
158 
does_not_move_in_evaluated(Obj && o)159 void does_not_move_in_evaluated(Obj&& o) {
160   // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
161   using result_t = decltype(std::move(o));
162   unsigned size = sizeof(std::move(o));
163   Obj moved = o;
164 }
165 
166 template <typename T1, typename T2>
167 struct mypair {
168   T1 first;
169   T2 second;
170 };
171 
moves_member_of_parameter(mypair<Obj,Obj> && pair)172 void moves_member_of_parameter(mypair<Obj, Obj>&& pair) {
173   // CHECK-MESSAGES-NOSUBEXPR: :[[@LINE-1]]:51: warning: rvalue reference parameter 'pair' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
174   Obj a = std::move(pair.first);
175   Obj b = std::move(pair.second);
176 }
177 
178 template <typename T>
179 struct myoptional {
180   T& operator*() &;
181   T&& operator*() &&;
182 };
183 
moves_deref_optional(myoptional<Obj> && opt)184 void moves_deref_optional(myoptional<Obj>&& opt) {
185   // CHECK-MESSAGES-NOSUBEXPR: :[[@LINE-1]]:45: warning: rvalue reference parameter 'opt' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
186   Obj other = std::move(*opt);
187 }
188 
moves_optional_then_deref_resulting_rvalue(myoptional<Obj> && opt)189 void moves_optional_then_deref_resulting_rvalue(myoptional<Obj>&& opt) {
190   Obj other = *std::move(opt);
191 }
192 
pass_by_lvalue_reference(Obj & o)193 void pass_by_lvalue_reference(Obj& o) {
194   o.member();
195 }
196 
pass_by_value(Obj o)197 void pass_by_value(Obj o) {
198   o.member();
199 }
200 
pass_by_const_lvalue_reference(const Obj & o)201 void pass_by_const_lvalue_reference(const Obj& o) {
202   o.member();
203 }
204 
pass_by_const_lvalue_reference(const Obj && o)205 void pass_by_const_lvalue_reference(const Obj&& o) {
206   o.member();
207 }
208 
lambda_captures_parameter_as_reference(Obj && o)209 void lambda_captures_parameter_as_reference(Obj&& o) {
210   auto f = [&o]() {
211     consumes_object(std::move(o));
212   };
213 }
214 
lambda_captures_parameter_as_reference_nested(Obj && o)215 void lambda_captures_parameter_as_reference_nested(Obj&& o) {
216   auto f = [&o]() {
217     auto f_nested = [&o]() {
218       auto f_nested2 = [&o]() {
219         consumes_object(std::move(o));
220       };
221     };
222   };
223 }
224 
225 #if __cplusplus >= 201402L
lambda_captures_parameter_generalized(Obj && o)226 void lambda_captures_parameter_generalized(Obj&& o) {
227   auto f = [o = std::move(o)]() {
228     consumes_object(std::move(o));
229   };
230 }
231 #endif
232 
negative_lambda_checks()233 void negative_lambda_checks() {
234   auto never_moves_nested = [](Obj&& o1) {
235     auto nested = [&]() {
236       Obj other{std::move(o1)};
237     };
238   };
239 
240 #if __cplusplus >= 201402L
241   auto auto_lvalue_ref_param = [](auto& o1) {
242     Obj other{o1};
243   };
244 
245   auto auto_forwarding_ref_param = [](auto&& o1) {
246     Obj other{o1};
247   };
248 
249   auto does_move_auto_rvalue_ref_param = [](auto&& o1) {
250     Obj other{std::forward(o1)};
251   };
252 #endif
253 
254   auto does_move = [](Obj&& o1) {
255     Obj other{std::move(o1)};
256   };
257 
258   auto not_rvalue_ref = [](Obj& o1) {
259     Obj other{std::move(o1)};
260   };
261 
262   Obj local;
263   auto captures = [local]() { };
264 }
265 
266 struct AClass {
member_with_lambda_no_moveAClass267   void member_with_lambda_no_move(Obj&& o) {
268     // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
269     auto captures_this = [=, this]() {
270       Obj other = std::move(o);
271     };
272   }
member_with_lambda_that_movesAClass273   void member_with_lambda_that_moves(Obj&& o) {
274     auto captures_this = [&, this]() {
275       Obj other = std::move(o);
276     };
277   }
278 };
279 
useless_move(Obj && o)280 void useless_move(Obj&& o) {
281   // FIXME - The object is not actually moved from - this should probably be
282   // flagged by *some* check. Which one?
283   std::move(o);
284 }
285 
286 template <typename>
287 class TemplatedClass;
288 
289 template <typename T>
unresolved_lookup(TemplatedClass<T> && o)290 void unresolved_lookup(TemplatedClass<T>&& o) {
291   TemplatedClass<T> moved = std::move(o);
292 }
293 
294 struct DefinesMove {
DefinesMoveDefinesMove295   DefinesMove(DefinesMove&& rhs) : o(std::move(rhs.o)) { }
operator =DefinesMove296   DefinesMove& operator=(DefinesMove&& rhs) {
297     if (this != &rhs) {
298       o = std::move(rhs.o);
299     }
300     return *this;
301   }
302   Obj o;
303 };
304 
305 struct DeclaresMove {
306   DeclaresMove(DeclaresMove&& rhs);
307   DeclaresMove& operator=(DeclaresMove&& rhs);
308 };
309 
310 struct AnotherObj {
AnotherObjAnotherObj311   AnotherObj(Obj&& o) : o(std::move(o)) {}
AnotherObjAnotherObj312   AnotherObj(Obj&& o, int) { o = std::move(o); }
313   Obj o;
314 };
315 
316 template <class T>
317 struct AClassTemplate {
AClassTemplateAClassTemplate318   AClassTemplate(T&& t) {}
319   // CHECK-MESSAGES-NONDEDUCED: :[[@LINE-1]]:22: warning: rvalue reference parameter 't' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
320 
movesAClassTemplate321   void moves(T&& t) {
322     T other = std::move(t);
323   }
never_movesAClassTemplate324   void never_moves(T&& t) {}
325   // CHECK-MESSAGES-NONDEDUCED: :[[@LINE-1]]:24: warning: rvalue reference parameter 't' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
326 };
327 
instantiate_a_class_template()328 void instantiate_a_class_template() {
329   Obj o;
330   AClassTemplate<Obj> withObj{std::move(o)};
331   withObj.never_moves(std::move(o));
332 
333   AClassTemplate<Obj&> withObjRef(o);
334   withObjRef.never_moves(o);
335 }
336 
337 namespace gh68209 {
f1(int && x)338   void f1([[maybe_unused]] int&& x) {}
339 
f2(int && x)340   void f2(__attribute__((unused)) int&& x) {}
341 
f3(int && x)342   void f3(int&& x) {}
343   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: rvalue reference parameter 'x' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
344 
345   template <typename T>
f4(T && x)346   void f4([[maybe_unused]] T&& x) {}
347 
348   template <typename T>
f5(__attribute ((unused))T && x)349   void f5(__attribute((unused)) T&& x) {}
350 
351   template<typename T>
f6(T && x)352   void f6(T&& x) {}
353 
f7(int && x)354   void f7([[maybe_unused]] int&& x) { x += 1; }
355   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: rvalue reference parameter 'x' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
356 
f8(int && x)357   void f8(__attribute__((unused)) int&& x) { x += 1; }
358   // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: rvalue reference parameter 'x' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]
359 } // namespace gh68209
360 
361 namespace gh69412 {
362   struct S
363   {
364       S(const int&);
365       S(int&&) = delete;
366 
367       void foo(int&&) = delete;
368   };
369 } // namespace gh69412
370