1 | // RUN: %clang_cc1 -fsyntax-only -Wloop-analysis -verify -std=c++17 %s |
2 | |
3 | struct S { |
4 | bool stop() { return false; } |
5 | bool keep_running; |
6 | }; |
7 | |
8 | void by_ref(int &value) { } |
9 | void by_value(int value) { } |
10 | void by_pointer(int *value) {} |
11 | |
12 | void test1() { |
13 | S s; |
14 | for (; !s.stop();) {} |
15 | for (; s.keep_running;) {} |
16 | for (int i; i < 1; ++i) {} |
17 | for (int i; i < 1; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
18 | for (int i; i < 1; ) { ++i; } |
19 | for (int i; i < 1; ) { return; } |
20 | for (int i; i < 1; ) { break; } |
21 | for (int i; i < 1; ) { goto exit_loop; } |
22 | exit_loop: |
23 | for (int i; i < 1; ) { by_ref(i); } |
24 | for (int i; i < 1; ) { by_value(i); } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
25 | for (int i; i < 1; ) { by_pointer(&i); } |
26 | |
27 | for (int i; i < 1; ++i) |
28 | for (int j; j < 1; ++j) |
29 | { } |
30 | for (int i; i < 1; ++i) |
31 | for (int j; j < 1; ++i) // expected-warning {{variable 'j' used in loop condition not modified in loop body}} |
32 | { } |
33 | for (int i; i < 1; ++i) |
34 | for (int j; i < 1; ++j) // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
35 | { } |
36 | |
37 | for (int *i, *j; i < j; ++i) {} |
38 | for (int *i, *j; i < j;) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}} |
39 | |
40 | // Dereferencing pointers is ignored for now. |
41 | for (int *i; *i; ) {} |
42 | } |
43 | |
44 | void test2() { |
45 | int i, j, k; |
46 | int *ptr; |
47 | |
48 | // Testing CastExpr |
49 | for (; i; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
50 | for (; i; ) { i = 5; } |
51 | |
52 | // Testing BinaryOperator |
53 | for (; i < j; ) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}} |
54 | for (; i < j; ) { i = 5; } |
55 | for (; i < j; ) { j = 5; } |
56 | |
57 | // Testing IntegerLiteral |
58 | for (; i < 5; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
59 | for (; i < 5; ) { i = 5; } |
60 | |
61 | // Testing FloatingLiteral |
62 | for (; i < 5.0; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
63 | for (; i < 5.0; ) { i = 5; } |
64 | |
65 | // Testing CharacterLiteral |
66 | for (; i == 'a'; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
67 | for (; i == 'a'; ) { i = 5; } |
68 | |
69 | // Testing CXXBoolLiteralExpr |
70 | for (; i == true; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
71 | for (; i == true; ) { i = 5; } |
72 | |
73 | // Testing GNUNullExpr |
74 | for (; ptr == __null; ) {} // expected-warning {{variable 'ptr' used in loop condition not modified in loop body}} |
75 | for (; ptr == __null; ) { ptr = &i; } |
76 | |
77 | // Testing UnaryOperator |
78 | for (; -i > 5; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
79 | for (; -i > 5; ) { ++i; } |
80 | |
81 | // Testing ImaginaryLiteral |
82 | for (; i != 3i; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
83 | for (; i != 3i; ) { ++i; } |
84 | |
85 | // Testing ConditionalOperator |
86 | for (; i ? j : k; ) {} // expected-warning {{variables 'i', 'j', and 'k' used in loop condition not modified in loop body}} |
87 | for (; i ? j : k; ) { ++i; } |
88 | for (; i ? j : k; ) { ++j; } |
89 | for (; i ? j : k; ) { ++k; } |
90 | for (; i; ) { j = i ? i : i; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
91 | for (; i; ) { j = (i = 1) ? i : i; } |
92 | for (; i; ) { j = i ? i : ++i; } |
93 | |
94 | // Testing BinaryConditionalOperator |
95 | for (; i ?: j; ) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}} |
96 | for (; i ?: j; ) { ++i; } |
97 | for (; i ?: j; ) { ++j; } |
98 | for (; i; ) { j = i ?: i; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
99 | |
100 | // Testing ParenExpr |
101 | for (; (i); ) { } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
102 | for (; (i); ) { ++i; } |
103 | |
104 | // Testing non-evaluated variables |
105 | for (; i < sizeof(j); ) { } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
106 | for (; i < sizeof(j); ) { ++j; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}} |
107 | for (; i < sizeof(j); ) { ++i; } |
108 | } |
109 | |
110 | // False positive and how to silence. |
111 | void test3() { |
112 | int x; |
113 | int *ptr = &x; |
114 | for (;x<5;) { *ptr = 6; } // expected-warning {{variable 'x' used in loop condition not modified in loop body}} |
115 | |
116 | for (;x<5;) { |
117 | *ptr = 6; |
118 | (void)x; |
119 | } |
120 | } |
121 | |
122 | // Check ordering and printing of variables. Max variables is currently 4. |
123 | void test4() { |
124 | int a, b, c, d, e, f; |
125 | for (; a;); // expected-warning {{variable 'a' used in loop condition not modified in loop body}} |
126 | for (; a + b;); // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}} |
127 | for (; a + b + c;); // expected-warning {{variables 'a', 'b', and 'c' used in loop condition not modified in loop body}} |
128 | for (; a + b + c + d;); // expected-warning {{variables 'a', 'b', 'c', and 'd' used in loop condition not modified in loop body}} |
129 | for (; a + b + c + d + e;); // expected-warning {{variables used in loop condition not modified in loop body}} |
130 | for (; a + b + c + d + e + f;); // expected-warning {{variables used in loop condition not modified in loop body}} |
131 | for (; a + c + d + b;); // expected-warning {{variables 'a', 'c', 'd', and 'b' used in loop condition not modified in loop body}} |
132 | for (; d + c + b + a;); // expected-warning {{variables 'd', 'c', 'b', and 'a' used in loop condition not modified in loop body}} |
133 | } |
134 | |
135 | // Ensure that the warning doesn't fail when lots of variables are used |
136 | // in the conditional. |
137 | void test5() { |
138 | for (int a; a+a+a+a+a+a+a+a+a+a;); // \ |
139 | // expected-warning {{variable 'a' used in loop condition not modified in loop body}} |
140 | for (int a; a+a+a+a+a+a+a+a+a+a+a;); // \ |
141 | // expected-warning {{variable 'a' used in loop condition not modified in loop body}} |
142 | for (int a; a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;); // \ |
143 | // expected-warning {{variable 'a' used in loop condition not modified in loop body}} |
144 | for (int a; a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;);//\ |
145 | // expected-warning {{variable 'a' used in loop condition not modified in loop body}} |
146 | } |
147 | |
148 | // Ignore global variables and static variables. |
149 | int x6; |
150 | void test6() { |
151 | static int y; |
152 | for (;x6;); |
153 | for (;y;); |
154 | } |
155 | |
156 | void test7() { |
157 | int i; |
158 | for (;;i++) { // expected-note{{incremented here}} |
159 | if (true) test7(); |
160 | i++; // expected-warning{{incremented both}} |
161 | } |
162 | for (;;i++) { // expected-note{{incremented here}} |
163 | if (true) break; |
164 | ++i; // expected-warning{{incremented both}} |
165 | } |
166 | for (;;++i) { // expected-note{{incremented here}} |
167 | while (true) return; |
168 | i++; // expected-warning{{incremented both}} |
169 | } |
170 | for (;;++i) { // expected-note{{incremented here}} |
171 | ++i; // expected-warning{{incremented both}} |
172 | } |
173 | |
174 | for (;;i--) { // expected-note{{decremented here}} |
175 | if (true) test7(); |
176 | i--; // expected-warning{{decremented both}} |
177 | } |
178 | for (;;i--) { // expected-note{{decremented here}} |
179 | if (true) break; |
180 | --i; // expected-warning{{decremented both}} |
181 | } |
182 | for (;;--i) { // expected-note{{decremented here}} |
183 | while (true) return; |
184 | i--; // expected-warning{{decremented both}} |
185 | } |
186 | for (;;--i) { // expected-note{{decremented here}} |
187 | --i; // expected-warning{{decremented both}} |
188 | } |
189 | |
190 | // Don't warn when loop is only one statement. |
191 | for (;;++i) |
192 | i++; |
193 | for (;;--i) |
194 | --i; |
195 | |
196 | // Don't warn when loop has continue statement. |
197 | for (;;i++) { |
198 | if (true) continue; |
199 | i++; |
200 | } |
201 | for (;;i--) { |
202 | if (true) continue; |
203 | i--; |
204 | } |
205 | |
206 | // But do warn if the continue is in a nested loop. |
207 | for (;;i--) { // expected-note{{decremented here}} |
208 | for (int j = 0; j < 10; ++j) continue; |
209 | i--; // expected-warning{{decremented both}} |
210 | } |
211 | } |
212 | |
213 | struct iterator { |
214 | iterator operator++() { return *this; } |
215 | iterator operator++(int) { return *this; } |
216 | iterator operator--() { return *this; } |
217 | iterator operator--(int) { return *this; } |
218 | }; |
219 | void test8() { |
220 | iterator i; |
221 | for (;;i++) { // expected-note{{incremented here}} |
222 | if (true) test7(); |
223 | i++; // expected-warning{{incremented both}} |
224 | } |
225 | for (;;i++) { // expected-note{{incremented here}} |
226 | if (true) break; |
227 | ++i; // expected-warning{{incremented both}} |
228 | } |
229 | for (;;++i) { // expected-note{{incremented here}} |
230 | while (true) return; |
231 | i++; // expected-warning{{incremented both}} |
232 | } |
233 | for (;;++i) { // expected-note{{incremented here}} |
234 | ++i; // expected-warning{{incremented both}} |
235 | } |
236 | |
237 | for (;;i--) { // expected-note{{decremented here}} |
238 | if (true) test7(); |
239 | i--; // expected-warning{{decremented both}} |
240 | } |
241 | for (;;i--) { // expected-note{{decremented here}} |
242 | if (true) break; |
243 | --i; // expected-warning{{decremented both}} |
244 | } |
245 | for (;;--i) { // expected-note{{decremented here}} |
246 | while (true) return; |
247 | i--; // expected-warning{{decremented both}} |
248 | } |
249 | for (;;--i) { // expected-note{{decremented here}} |
250 | --i; // expected-warning{{decremented both}} |
251 | } |
252 | |
253 | // Don't warn when loop is only one statement. |
254 | for (;;++i) |
255 | i++; |
256 | for (;;--i) |
257 | --i; |
258 | |
259 | // Don't warn when loop has continue statement. |
260 | for (;;i++) { |
261 | if (true) continue; |
262 | i++; |
263 | } |
264 | for (;;i--) { |
265 | if (true) continue; |
266 | i--; |
267 | } |
268 | |
269 | // But do warn if the continue is in a nested loop. |
270 | for (;;i--) { // expected-note{{decremented here}} |
271 | for (int j = 0; j < 10; ++j) continue; |
272 | i--; // expected-warning{{decremented both}} |
273 | } |
274 | } |
275 | |
276 | int f(int); |
277 | void test9() { |
278 | // Don't warn when variable is defined by the loop condition. |
279 | for (int i = 0; int x = f(i); ++i) {} |
280 | } |
281 | |
282 | // Don't warn when decomposition variables are in the loop condition. |
283 | // TODO: BindingDecl's which make a copy should warn. |
284 | void test10() { |
285 | int arr[] = {1, 2, 3}; |
286 | for (auto[i, j, k] = arr;;) { } |
287 | for (auto[i, j, k] = arr; i < j; ++i, ++j) { } |
288 | |
289 | for (auto[i, j, k] = arr; i;) { } |
290 | for (auto[i, j, k] = arr; i < j;) { } |
291 | for (auto[i, j, k] = arr; i < j; ++arr[0]) { } |
292 | |
293 | int a = 1, b = 2; |
294 | for (auto[i, j, k] = arr; a < b;) { } // expected-warning{{variables 'a' and 'b' used in loop condition not modified in loop body}} |
295 | for (auto[i, j, k] = arr; a < b; ++a) { } |
296 | |
297 | for (auto [i, j, k] = arr; i < a;) { } |
298 | for (auto[i, j, k] = arr; i < a; ++a) { } |
299 | for (auto[i, j, k] = arr; i < a; ++i) { } |
300 | for (auto[i, j, k] = arr; i < a; ++arr[0]) { } |
301 | }; |
302 | |