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
13namespace std {
14template <typename>
15struct remove_reference;
16
17template <typename _Tp> struct remove_reference { typedef _Tp type; };
18template <typename _Tp> struct remove_reference<_Tp&> { typedef _Tp type; };
19template <typename _Tp> struct remove_reference<_Tp&&> { typedef _Tp type; };
20
21template <typename _Tp>
22constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept;
23
24template <typename _Tp>
25constexpr _Tp &&
26forward(typename remove_reference<_Tp>::type &__t) noexcept;
27
28}
29// NOLINTEND
30
31struct 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
40void consumes_object(Obj);
41
42void 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
47void just_a_declaration(Obj&& o);
48
49void 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
54template <typename T>
55void 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
60void 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
65void 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
71void 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
74void 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
78void 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
85void 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
113void 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
127template <typename T>
128void forwarding_ref(T&& t) {
129 t.member();
130}
131
132template <typename T>
133void forwarding_ref_forwarded(T&& t) {
134 forwarding_ref(std::forward<T>(t));
135}
136
137template <typename... Ts>
138void type_pack(Ts&&... ts) {
139 (forwarding_ref(std::forward<Ts>(ts)), ...);
140}
141
142void call_forwarding_functions() {
143 Obj o;
144
145 forwarding_ref(t: Obj{});
146 type_pack(ts: Obj{});
147 type_pack(ts: Obj{}, ts&: o);
148 type_pack(ts: Obj{}, ts: Obj{});
149}
150
151void moves_parameter(Obj&& o) {
152 Obj moved = std::move(o);
153}
154
155void moves_parameter_extra_parens(Obj&& o) {
156 Obj moved = std::move((o));
157}
158
159void 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
166template <typename T1, typename T2>
167struct mypair {
168 T1 first;
169 T2 second;
170};
171
172void 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
178template <typename T>
179struct myoptional {
180 T& operator*() &;
181 T&& operator*() &&;
182};
183
184void 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
189void moves_optional_then_deref_resulting_rvalue(myoptional<Obj>&& opt) {
190 Obj other = *std::move(opt);
191}
192
193void pass_by_lvalue_reference(Obj& o) {
194 o.member();
195}
196
197void pass_by_value(Obj o) {
198 o.member();
199}
200
201void pass_by_const_lvalue_reference(const Obj& o) {
202 o.member();
203}
204
205void pass_by_const_lvalue_reference(const Obj&& o) {
206 o.member();
207}
208
209void lambda_captures_parameter_as_reference(Obj&& o) {
210 auto f = [&o]() {
211 consumes_object(std::move(o));
212 };
213}
214
215void 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
226void lambda_captures_parameter_generalized(Obj&& o) {
227 auto f = [o = std::move(o)]() {
228 consumes_object(std::move(o));
229 };
230}
231#endif
232
233void 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
266struct AClass {
267 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 }
273 void member_with_lambda_that_moves(Obj&& o) {
274 auto captures_this = [&, this]() {
275 Obj other = std::move(o);
276 };
277 }
278};
279
280void 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
286template <typename>
287class TemplatedClass;
288
289template <typename T>
290void unresolved_lookup(TemplatedClass<T>&& o) {
291 TemplatedClass<T> moved = std::move(o);
292}
293
294struct DefinesMove {
295 DefinesMove(DefinesMove&& rhs) : o(std::move(rhs.o)) { }
296 DefinesMove& operator=(DefinesMove&& rhs) {
297 if (this != &rhs) {
298 o = std::move(rhs.o);
299 }
300 return *this;
301 }
302 Obj o;
303};
304
305struct DeclaresMove {
306 DeclaresMove(DeclaresMove&& rhs);
307 DeclaresMove& operator=(DeclaresMove&& rhs);
308};
309
310struct AnotherObj {
311 AnotherObj(Obj&& o) : o(std::move(o)) {}
312 AnotherObj(Obj&& o, int) { o = std::move(o); }
313 Obj o;
314};
315
316template <class T>
317struct AClassTemplate {
318 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
321 void moves(T&& t) {
322 T other = std::move(t);
323 }
324 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
328void instantiate_a_class_template() {
329 Obj o;
330 AClassTemplate<Obj> withObj{std::move(o)};
331 withObj.never_moves(t: std::move(o));
332
333 AClassTemplate<Obj&> withObjRef(o);
334 withObjRef.never_moves(t&: o);
335}
336
337namespace gh68209 {
338 void f1([[maybe_unused]] int&& x) {}
339
340 void f2(__attribute__((unused)) int&& x) {}
341
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>
346 void f4([[maybe_unused]] T&& x) {}
347
348 template <typename T>
349 void f5(__attribute((unused)) T&& x) {}
350
351 template<typename T>
352 void f6(T&& x) {}
353
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
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
361namespace gh69412 {
362 struct S
363 {
364 S(const int&);
365 S(int&&) = delete;
366
367 void foo(int&&) = delete;
368 };
369} // namespace gh69412
370

source code of clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp