// 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]) { } };