blob: 324dd386292acd6af56e363c2089f988fdabd6d4 [file] [log] [blame]
// RUN: %clang_cc1 -fsyntax-only -Wloop-analysis -verify -std=c++17 %s
struct S {
bool stop() { return false; }
bool keep_running;
};
void by_ref(int &value) { }
void by_value(int value) { }
void by_pointer(int *value) {}
void test1() {
S s;
for (; !s.stop();) {}
for (; s.keep_running;) {}
for (int i; i < 1; ++i) {}
for (int i; i < 1; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (int i; i < 1; ) { ++i; }
for (int i; i < 1; ) { return; }
for (int i; i < 1; ) { break; }
for (int i; i < 1; ) { goto exit_loop; }
exit_loop:
for (int i; i < 1; ) { by_ref(i); }
for (int i; i < 1; ) { by_value(i); } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (int i; i < 1; ) { by_pointer(&i); }
for (int i; i < 1; ++i)
for (int j; j < 1; ++j)
{ }
for (int i; i < 1; ++i)
for (int j; j < 1; ++i) // expected-warning {{variable 'j' used in loop condition not modified in loop body}}
{ }
for (int i; i < 1; ++i)
for (int j; i < 1; ++j) // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
{ }
for (int *i, *j; i < j; ++i) {}
for (int *i, *j; i < j;) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}}
// Dereferencing pointers is ignored for now.
for (int *i; *i; ) {}
}
void test2() {
int i, j, k;
int *ptr;
// Testing CastExpr
for (; i; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i; ) { i = 5; }
// Testing BinaryOperator
for (; i < j; ) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}}
for (; i < j; ) { i = 5; }
for (; i < j; ) { j = 5; }
// Testing IntegerLiteral
for (; i < 5; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i < 5; ) { i = 5; }
// Testing FloatingLiteral
for (; i < 5.0; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i < 5.0; ) { i = 5; }
// Testing CharacterLiteral
for (; i == 'a'; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i == 'a'; ) { i = 5; }
// Testing CXXBoolLiteralExpr
for (; i == true; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i == true; ) { i = 5; }
// Testing GNUNullExpr
for (; ptr == __null; ) {} // expected-warning {{variable 'ptr' used in loop condition not modified in loop body}}
for (; ptr == __null; ) { ptr = &i; }
// Testing UnaryOperator
for (; -i > 5; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; -i > 5; ) { ++i; }
// Testing ImaginaryLiteral
for (; i != 3i; ) {} // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i != 3i; ) { ++i; }
// Testing ConditionalOperator
for (; i ? j : k; ) {} // expected-warning {{variables 'i', 'j', and 'k' used in loop condition not modified in loop body}}
for (; i ? j : k; ) { ++i; }
for (; i ? j : k; ) { ++j; }
for (; i ? j : k; ) { ++k; }
for (; i; ) { j = i ? i : i; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i; ) { j = (i = 1) ? i : i; }
for (; i; ) { j = i ? i : ++i; }
// Testing BinaryConditionalOperator
for (; i ?: j; ) {} // expected-warning {{variables 'i' and 'j' used in loop condition not modified in loop body}}
for (; i ?: j; ) { ++i; }
for (; i ?: j; ) { ++j; }
for (; i; ) { j = i ?: i; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
// Testing ParenExpr
for (; (i); ) { } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; (i); ) { ++i; }
// Testing non-evaluated variables
for (; i < sizeof(j); ) { } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i < sizeof(j); ) { ++j; } // expected-warning {{variable 'i' used in loop condition not modified in loop body}}
for (; i < sizeof(j); ) { ++i; }
}
// False positive and how to silence.
void test3() {
int x;
int *ptr = &x;
for (;x<5;) { *ptr = 6; } // expected-warning {{variable 'x' used in loop condition not modified in loop body}}
for (;x<5;) {
*ptr = 6;
(void)x;
}
}
// Check ordering and printing of variables. Max variables is currently 4.
void test4() {
int a, b, c, d, e, f;
for (; a;); // expected-warning {{variable 'a' used in loop condition not modified in loop body}}
for (; a + b;); // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}}
for (; a + b + c;); // expected-warning {{variables 'a', 'b', and 'c' used in loop condition not modified in loop body}}
for (; a + b + c + d;); // expected-warning {{variables 'a', 'b', 'c', and 'd' used in loop condition not modified in loop body}}
for (; a + b + c + d + e;); // expected-warning {{variables used in loop condition not modified in loop body}}
for (; a + b + c + d + e + f;); // expected-warning {{variables used in loop condition not modified in loop body}}
for (; a + c + d + b;); // expected-warning {{variables 'a', 'c', 'd', and 'b' used in loop condition not modified in loop body}}
for (; d + c + b + a;); // expected-warning {{variables 'd', 'c', 'b', and 'a' used in loop condition not modified in loop body}}
}
// Ensure that the warning doesn't fail when lots of variables are used
// in the conditional.
void test5() {
for (int a; a+a+a+a+a+a+a+a+a+a;); // \
// expected-warning {{variable 'a' used in loop condition not modified in loop body}}
for (int a; a+a+a+a+a+a+a+a+a+a+a;); // \
// expected-warning {{variable 'a' used in loop condition not modified in loop body}}
for (int a; a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;); // \
// expected-warning {{variable 'a' used in loop condition not modified in loop body}}
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;);//\
// expected-warning {{variable 'a' used in loop condition not modified in loop body}}
}
// Ignore global variables and static variables.
int x6;
void test6() {
static int y;
for (;x6;);
for (;y;);
}
void test7() {
int i;
for (;;i++) { // expected-note{{incremented here}}
if (true) test7();
i++; // expected-warning{{incremented both}}
}
for (;;i++) { // expected-note{{incremented here}}
if (true) break;
++i; // expected-warning{{incremented both}}
}
for (;;++i) { // expected-note{{incremented here}}
while (true) return;
i++; // expected-warning{{incremented both}}
}
for (;;++i) { // expected-note{{incremented here}}
++i; // expected-warning{{incremented both}}
}
for (;;i--) { // expected-note{{decremented here}}
if (true) test7();
i--; // expected-warning{{decremented both}}
}
for (;;i--) { // expected-note{{decremented here}}
if (true) break;
--i; // expected-warning{{decremented both}}
}
for (;;--i) { // expected-note{{decremented here}}
while (true) return;
i--; // expected-warning{{decremented both}}
}
for (;;--i) { // expected-note{{decremented here}}
--i; // expected-warning{{decremented both}}
}
// Don't warn when loop is only one statement.
for (;;++i)
i++;
for (;;--i)
--i;
// Don't warn when loop has continue statement.
for (;;i++) {
if (true) continue;
i++;
}
for (;;i--) {
if (true) continue;
i--;
}
// But do warn if the continue is in a nested loop.
for (;;i--) { // expected-note{{decremented here}}
for (int j = 0; j < 10; ++j) continue;
i--; // expected-warning{{decremented both}}
}
}
struct iterator {
iterator operator++() { return *this; }
iterator operator++(int) { return *this; }
iterator operator--() { return *this; }
iterator operator--(int) { return *this; }
};
void test8() {
iterator i;
for (;;i++) { // expected-note{{incremented here}}
if (true) test7();
i++; // expected-warning{{incremented both}}
}
for (;;i++) { // expected-note{{incremented here}}
if (true) break;
++i; // expected-warning{{incremented both}}
}
for (;;++i) { // expected-note{{incremented here}}
while (true) return;
i++; // expected-warning{{incremented both}}
}
for (;;++i) { // expected-note{{incremented here}}
++i; // expected-warning{{incremented both}}
}
for (;;i--) { // expected-note{{decremented here}}
if (true) test7();
i--; // expected-warning{{decremented both}}
}
for (;;i--) { // expected-note{{decremented here}}
if (true) break;
--i; // expected-warning{{decremented both}}
}
for (;;--i) { // expected-note{{decremented here}}
while (true) return;
i--; // expected-warning{{decremented both}}
}
for (;;--i) { // expected-note{{decremented here}}
--i; // expected-warning{{decremented both}}
}
// Don't warn when loop is only one statement.
for (;;++i)
i++;
for (;;--i)
--i;
// Don't warn when loop has continue statement.
for (;;i++) {
if (true) continue;
i++;
}
for (;;i--) {
if (true) continue;
i--;
}
// But do warn if the continue is in a nested loop.
for (;;i--) { // expected-note{{decremented here}}
for (int j = 0; j < 10; ++j) continue;
i--; // expected-warning{{decremented both}}
}
}
int f(int);
void test9() {
// Don't warn when variable is defined by the loop condition.
for (int i = 0; int x = f(i); ++i) {}
}
// Don't warn when decomposition variables are in the loop condition.
// TODO: BindingDecl's which make a copy should warn.
void test10() {
int arr[] = {1, 2, 3};
for (auto[i, j, k] = arr;;) { }
for (auto[i, j, k] = arr; i < j; ++i, ++j) { }
for (auto[i, j, k] = arr; i;) { }
for (auto[i, j, k] = arr; i < j;) { }
for (auto[i, j, k] = arr; i < j; ++arr[0]) { }
int a = 1, b = 2;
for (auto[i, j, k] = arr; a < b;) { } // expected-warning{{variables 'a' and 'b' used in loop condition not modified in loop body}}
for (auto[i, j, k] = arr; a < b; ++a) { }
for (auto [i, j, k] = arr; i < a;) { }
for (auto[i, j, k] = arr; i < a; ++a) { }
for (auto[i, j, k] = arr; i < a; ++i) { }
for (auto[i, j, k] = arr; i < a; ++arr[0]) { }
};