1 // RUN: %clang_cc1 -fsyntax-only -Wloop-analysis -verify -std=c++17 %s
2 
3 struct S {
stopS4   bool stop() { return false; }
5   bool keep_running;
6 };
7 
by_ref(int & value)8 void by_ref(int &value) { }
by_value(int value)9 void by_value(int value) { }
by_pointer(int * value)10 void by_pointer(int *value) {}
11 
test1()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 
test2()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.
test3()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.
test4()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.
test5()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;
test6()150 void test6() {
151   static int y;
152   for (;x6;);
153   for (;y;);
154 }
155 
test7()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 {
operator ++iterator214   iterator operator++() { return *this; }
operator ++iterator215   iterator operator++(int) { return *this; }
operator --iterator216   iterator operator--() { return *this; }
operator --iterator217   iterator operator--(int) { return *this; }
218 };
test8()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);
test9()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.
test10()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