302 lines
10 KiB
C++
302 lines
10 KiB
C++
|
// 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]) { }
|
||
|
};
|