1 | // RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11 -verify %s |
2 | // RUN: %clang_cc1 -fsyntax-only -Wpessimizing-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s |
3 | |
4 | // definitions for std::move |
5 | namespace std { |
6 | inline namespace foo { |
7 | template <class T> struct remove_reference { typedef T type; }; |
8 | template <class T> struct remove_reference<T&> { typedef T type; }; |
9 | template <class T> struct remove_reference<T&&> { typedef T type; }; |
10 | |
11 | template <class T> typename remove_reference<T>::type &&move(T &&t); |
12 | } |
13 | } |
14 | |
15 | struct A {}; |
16 | struct B { |
17 | B() {} |
18 | B(A) {} |
19 | }; |
20 | |
21 | A test1(A a1) { |
22 | A a2; |
23 | return a1; |
24 | return a2; |
25 | return std::move(a1); |
26 | return std::move(a2); |
27 | // expected-warning@-1{{prevents copy elision}} |
28 | // expected-note@-2{{remove std::move call}} |
29 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
30 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" |
31 | } |
32 | |
33 | B test2(A a1, B b1) { |
34 | // Object is different than return type so don't warn. |
35 | A a2; |
36 | return a1; |
37 | return a2; |
38 | return std::move(a1); |
39 | return std::move(a2); |
40 | |
41 | B b2; |
42 | return b1; |
43 | return b2; |
44 | return std::move(b1); |
45 | return std::move(b2); |
46 | // expected-warning@-1{{prevents copy elision}} |
47 | // expected-note@-2{{remove std::move call}} |
48 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
49 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" |
50 | } |
51 | |
52 | A global_a; |
53 | A test3() { |
54 | // Don't warn when object is not local. |
55 | return global_a; |
56 | return std::move(global_a); |
57 | static A static_a; |
58 | return static_a; |
59 | return std::move(static_a); |
60 | |
61 | } |
62 | |
63 | A test4() { |
64 | return A(); |
65 | return test3(); |
66 | |
67 | return std::move(A()); |
68 | // expected-warning@-1{{prevents copy elision}} |
69 | // expected-note@-2{{remove std::move call}} |
70 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
71 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" |
72 | return std::move(test3()); |
73 | // expected-warning@-1{{prevents copy elision}} |
74 | // expected-note@-2{{remove std::move call}} |
75 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
76 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:"" |
77 | } |
78 | |
79 | void test5(A) { |
80 | test5(A()); |
81 | test5(test4()); |
82 | |
83 | test5(std::move(A())); |
84 | // expected-warning@-1{{prevents copy elision}} |
85 | // expected-note@-2{{remove std::move call}} |
86 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:"" |
87 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" |
88 | test5(std::move(test4())); |
89 | // expected-warning@-1{{prevents copy elision}} |
90 | // expected-note@-2{{remove std::move call}} |
91 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:19}:"" |
92 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:"" |
93 | } |
94 | |
95 | void test6() { |
96 | A a1 = A(); |
97 | A a2 = test3(); |
98 | |
99 | A a3 = std::move(A()); |
100 | // expected-warning@-1{{prevents copy elision}} |
101 | // expected-note@-2{{remove std::move call}} |
102 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
103 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" |
104 | A a4 = std::move(test3()); |
105 | // expected-warning@-1{{prevents copy elision}} |
106 | // expected-note@-2{{remove std::move call}} |
107 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
108 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:27-[[@LINE-4]]:28}:"" |
109 | } |
110 | |
111 | A test7() { |
112 | A a1 = std::move(A()); |
113 | // expected-warning@-1{{prevents copy elision}} |
114 | // expected-note@-2{{remove std::move call}} |
115 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
116 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" |
117 | A a2 = std::move((A())); |
118 | // expected-warning@-1{{prevents copy elision}} |
119 | // expected-note@-2{{remove std::move call}} |
120 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
121 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:"" |
122 | A a3 = (std::move(A())); |
123 | // expected-warning@-1{{prevents copy elision}} |
124 | // expected-note@-2{{remove std::move call}} |
125 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" |
126 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:"" |
127 | A a4 = (std::move((A()))); |
128 | // expected-warning@-1{{prevents copy elision}} |
129 | // expected-note@-2{{remove std::move call}} |
130 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" |
131 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:27}:"" |
132 | |
133 | return std::move(a1); |
134 | // expected-warning@-1{{prevents copy elision}} |
135 | // expected-note@-2{{remove std::move call}} |
136 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
137 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:22-[[@LINE-4]]:23}:"" |
138 | return std::move((a1)); |
139 | // expected-warning@-1{{prevents copy elision}} |
140 | // expected-note@-2{{remove std::move call}} |
141 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
142 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:24-[[@LINE-4]]:25}:"" |
143 | return (std::move(a1)); |
144 | // expected-warning@-1{{prevents copy elision}} |
145 | // expected-note@-2{{remove std::move call}} |
146 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" |
147 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" |
148 | return (std::move((a1))); |
149 | // expected-warning@-1{{prevents copy elision}} |
150 | // expected-note@-2{{remove std::move call}} |
151 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:21}:"" |
152 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:26}:"" |
153 | } |
154 | |
155 | #define wrap1(x) x |
156 | #define wrap2(x) x |
157 | |
158 | // Macro test. Since the std::move call is outside the macro, it is |
159 | // safe to suggest a fix-it. |
160 | A test8() { |
161 | A a; |
162 | return std::move(a); |
163 | // expected-warning@-1{{prevents copy elision}} |
164 | // expected-note@-2{{remove std::move call}} |
165 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
166 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:"" |
167 | return std::move(wrap1(a)); |
168 | // expected-warning@-1{{prevents copy elision}} |
169 | // expected-note@-2{{remove std::move call}} |
170 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
171 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:28-[[@LINE-4]]:29}:"" |
172 | return std::move(wrap1(wrap2(a))); |
173 | // expected-warning@-1{{prevents copy elision}} |
174 | // expected-note@-2{{remove std::move call}} |
175 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:"" |
176 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:35-[[@LINE-4]]:36}:"" |
177 | } |
178 | |
179 | #define test9 \ |
180 | A test9() { \ |
181 | A a; \ |
182 | return std::move(a); \ |
183 | } |
184 | |
185 | // Macro test. The std::call is inside the macro, so no fix-it is suggested. |
186 | test9 |
187 | // expected-warning@-1{{prevents copy elision}} |
188 | // CHECK-NOT: fix-it |
189 | |
190 | #define return_a return std::move(a) |
191 | |
192 | // Macro test. The std::call is inside the macro, so no fix-it is suggested. |
193 | A test10() { |
194 | A a; |
195 | return_a; |
196 | // expected-warning@-1{{prevents copy elision}} |
197 | // CHECK-NOT: fix-it |
198 | } |
199 | |
200 | namespace templates { |
201 | struct A {}; |
202 | struct B { B(A); }; |
203 | |
204 | // Warn once here since the type is not dependent. |
205 | template <typename T> |
206 | A test1() { |
207 | A a; |
208 | return std::move(a); |
209 | // expected-warning@-1{{prevents copy elision}} |
210 | // expected-note@-2{{remove std::move call}} |
211 | // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:12-[[@LINE-3]]:22}:"" |
212 | // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:23-[[@LINE-4]]:24}:"" |
213 | } |
214 | void run_test1() { |
215 | test1<A>(); |
216 | test1<B>(); |
217 | } |
218 | |
219 | // T1 and T2 may not be the same, the warning may not always apply. |
220 | template <typename T1, typename T2> |
221 | T1 test2() { |
222 | T2 t; |
223 | return std::move(t); |
224 | } |
225 | void run_test2() { |
226 | test2<A, A>(); |
227 | test2<B, A>(); |
228 | } |
229 | } |
230 | |