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 | |
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 | |
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> |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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> |
128 | void forwarding_ref(T&& t) { |
129 | t.member(); |
130 | } |
131 | |
132 | template <typename T> |
133 | void forwarding_ref_forwarded(T&& t) { |
134 | forwarding_ref(std::forward<T>(t)); |
135 | } |
136 | |
137 | template <typename... Ts> |
138 | void type_pack(Ts&&... ts) { |
139 | (forwarding_ref(std::forward<Ts>(ts)), ...); |
140 | } |
141 | |
142 | void 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 | |
151 | void moves_parameter(Obj&& o) { |
152 | Obj moved = std::move(o); |
153 | } |
154 | |
155 | void (Obj&& o) { |
156 | Obj moved = std::move((o)); |
157 | } |
158 | |
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 | |
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 | |
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 | |
189 | void moves_optional_then_deref_resulting_rvalue(myoptional<Obj>&& opt) { |
190 | Obj other = *std::move(opt); |
191 | } |
192 | |
193 | void pass_by_lvalue_reference(Obj& o) { |
194 | o.member(); |
195 | } |
196 | |
197 | void pass_by_value(Obj o) { |
198 | o.member(); |
199 | } |
200 | |
201 | void pass_by_const_lvalue_reference(const Obj& o) { |
202 | o.member(); |
203 | } |
204 | |
205 | void pass_by_const_lvalue_reference(const Obj&& o) { |
206 | o.member(); |
207 | } |
208 | |
209 | void lambda_captures_parameter_as_reference(Obj&& o) { |
210 | auto f = [&o]() { |
211 | consumes_object(std::move(o)); |
212 | }; |
213 | } |
214 | |
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 |
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 | |
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 { |
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 | |
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> |
290 | void unresolved_lookup(TemplatedClass<T>&& o) { |
291 | TemplatedClass<T> moved = std::move(o); |
292 | } |
293 | |
294 | struct 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 | |
305 | struct DeclaresMove { |
306 | DeclaresMove(DeclaresMove&& rhs); |
307 | DeclaresMove& operator=(DeclaresMove&& rhs); |
308 | }; |
309 | |
310 | struct AnotherObj { |
311 | AnotherObj(Obj&& o) : o(std::move(o)) {} |
312 | AnotherObj(Obj&& o, int) { o = std::move(o); } |
313 | Obj o; |
314 | }; |
315 | |
316 | template <class T> |
317 | struct 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 | |
328 | void 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 | |
337 | namespace 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 | |
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 | |