189a1d03eSRichard // RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
289a1d03eSRichard // RUN: -- -- -fexceptions -fblocks -fno-delayed-template-parsing
389a1d03eSRichard
simple_infinite_loop1()489a1d03eSRichard void simple_infinite_loop1() {
589a1d03eSRichard int i = 0;
689a1d03eSRichard int j = 0;
789a1d03eSRichard while (i < 10) {
889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
989a1d03eSRichard j++;
1089a1d03eSRichard }
1189a1d03eSRichard
1289a1d03eSRichard while (int k = 10) {
1389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop]
1489a1d03eSRichard j--;
1589a1d03eSRichard }
1689a1d03eSRichard
1789a1d03eSRichard while (int k = 10) {
1889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; it does not check any variables in the condition [bugprone-infinite-loop]
1989a1d03eSRichard k--;
2089a1d03eSRichard }
2189a1d03eSRichard
2289a1d03eSRichard do {
2389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
2489a1d03eSRichard j++;
2589a1d03eSRichard } while (i < 10);
2689a1d03eSRichard
2789a1d03eSRichard for (i = 0; i < 10; ++j) {
2889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
2989a1d03eSRichard }
3089a1d03eSRichard }
3189a1d03eSRichard
simple_infinite_loop2()3289a1d03eSRichard void simple_infinite_loop2() {
3389a1d03eSRichard int i = 0;
3489a1d03eSRichard int j = 0;
3589a1d03eSRichard int Limit = 10;
3689a1d03eSRichard while (i < Limit) {
3789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
3889a1d03eSRichard j++;
3989a1d03eSRichard }
4089a1d03eSRichard
4189a1d03eSRichard while (int k = Limit) {
4289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop]
4389a1d03eSRichard j--;
4489a1d03eSRichard }
4589a1d03eSRichard
4689a1d03eSRichard while (int k = Limit) {
4789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (Limit) are updated in the loop body [bugprone-infinite-loop]
4889a1d03eSRichard k--;
4989a1d03eSRichard }
5089a1d03eSRichard
5189a1d03eSRichard do {
5289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
5389a1d03eSRichard j++;
5489a1d03eSRichard } while (i < Limit);
5589a1d03eSRichard
5689a1d03eSRichard for (i = 0; i < Limit; ++j) {
5789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
5889a1d03eSRichard }
5989a1d03eSRichard }
6089a1d03eSRichard
simple_not_infinite1()6189a1d03eSRichard void simple_not_infinite1() {
6289a1d03eSRichard int i = 0;
6389a1d03eSRichard int Limit = 100;
6489a1d03eSRichard while (i < Limit) {
6589a1d03eSRichard // Not an error since 'Limit' is updated.
6689a1d03eSRichard Limit--;
6789a1d03eSRichard }
6889a1d03eSRichard
6989a1d03eSRichard while (Limit--) {
7089a1d03eSRichard // Not an error since 'Limit' is updated.
7189a1d03eSRichard i++;
7289a1d03eSRichard }
7389a1d03eSRichard
7489a1d03eSRichard while ((Limit)--) {
7589a1d03eSRichard // Not an error since 'Limit' is updated.
7689a1d03eSRichard i++;
7789a1d03eSRichard }
7889a1d03eSRichard
7989a1d03eSRichard while ((Limit) -= 1) {
8089a1d03eSRichard // Not an error since 'Limit' is updated.
8189a1d03eSRichard }
8289a1d03eSRichard
8389a1d03eSRichard while (int k = Limit) {
8489a1d03eSRichard // Not an error since 'Limit' is updated.
8589a1d03eSRichard Limit--;
8689a1d03eSRichard }
8789a1d03eSRichard
8889a1d03eSRichard while (int k = Limit) {
8989a1d03eSRichard // Not an error since 'Limit' is updated
9089a1d03eSRichard (Limit)--;
9189a1d03eSRichard }
9289a1d03eSRichard
9389a1d03eSRichard while (int k = Limit--) {
9489a1d03eSRichard // Not an error since 'Limit' is updated.
9589a1d03eSRichard i++;
9689a1d03eSRichard }
9789a1d03eSRichard
9889a1d03eSRichard do {
9989a1d03eSRichard Limit--;
10089a1d03eSRichard } while (i < Limit);
10189a1d03eSRichard
10289a1d03eSRichard for (i = 0; i < Limit; Limit--) {
10389a1d03eSRichard }
10489a1d03eSRichard
10589a1d03eSRichard for (i = 0; i < Limit; (Limit) = Limit - 1) {
10689a1d03eSRichard }
10789a1d03eSRichard
10889a1d03eSRichard for (i = 0; i < Limit; (Limit) -= 1) {
10989a1d03eSRichard }
11089a1d03eSRichard
11189a1d03eSRichard for (i = 0; i < Limit; --(Limit)) {
11289a1d03eSRichard }
11389a1d03eSRichard }
11489a1d03eSRichard
simple_not_infinite2()11589a1d03eSRichard void simple_not_infinite2() {
11689a1d03eSRichard for (int i = 10; i-- > 0;) {
11789a1d03eSRichard // Not an error, since loop variable is modified in its condition part.
11889a1d03eSRichard }
11989a1d03eSRichard }
12089a1d03eSRichard
12189a1d03eSRichard int unknown_function();
12289a1d03eSRichard
function_call()12389a1d03eSRichard void function_call() {
12489a1d03eSRichard int i = 0;
12589a1d03eSRichard while (i < unknown_function()) {
12689a1d03eSRichard // Not an error, since the function may return different values.
12789a1d03eSRichard }
12889a1d03eSRichard
12989a1d03eSRichard do {
13089a1d03eSRichard // Not an error, since the function may return different values.
13189a1d03eSRichard } while (i < unknown_function());
13289a1d03eSRichard
13389a1d03eSRichard for (i = 0; i < unknown_function();) {
13489a1d03eSRichard // Not an error, since the function may return different values.
13589a1d03eSRichard }
13689a1d03eSRichard }
13789a1d03eSRichard
escape_before1()13889a1d03eSRichard void escape_before1() {
13989a1d03eSRichard int i = 0;
14089a1d03eSRichard int Limit = 100;
14189a1d03eSRichard int *p = &i;
14289a1d03eSRichard while (i < Limit) {
14389a1d03eSRichard // Not an error, since *p is alias of i.
14489a1d03eSRichard (*p)++;
14589a1d03eSRichard }
14689a1d03eSRichard
14789a1d03eSRichard do {
14889a1d03eSRichard (*p)++;
14989a1d03eSRichard } while (i < Limit);
15089a1d03eSRichard
15189a1d03eSRichard for (i = 0; i < Limit; ++(*p)) {
15289a1d03eSRichard }
15389a1d03eSRichard }
15489a1d03eSRichard
escape_before2()15589a1d03eSRichard void escape_before2() {
15689a1d03eSRichard int i = 0;
15789a1d03eSRichard int Limit = 100;
15889a1d03eSRichard int &ii = i;
15989a1d03eSRichard while (i < Limit) {
16089a1d03eSRichard // Not an error, since ii is alias of i.
16189a1d03eSRichard ii++;
16289a1d03eSRichard }
16389a1d03eSRichard
16489a1d03eSRichard do {
16589a1d03eSRichard ii++;
16689a1d03eSRichard } while (i < Limit);
16789a1d03eSRichard
16889a1d03eSRichard for (i = 0; i < Limit; ++ii) {
16989a1d03eSRichard }
17089a1d03eSRichard }
17189a1d03eSRichard
escape_inside1()17289a1d03eSRichard void escape_inside1() {
17389a1d03eSRichard int i = 0;
17489a1d03eSRichard int Limit = 100;
17589a1d03eSRichard int *p = &i;
17689a1d03eSRichard while (i < Limit) {
17789a1d03eSRichard // Not an error, since *p is alias of i.
17889a1d03eSRichard int *p = &i;
17989a1d03eSRichard (*p)++;
18089a1d03eSRichard }
18189a1d03eSRichard
18289a1d03eSRichard do {
18389a1d03eSRichard int *p = &i;
18489a1d03eSRichard (*p)++;
18589a1d03eSRichard } while (i < Limit);
18689a1d03eSRichard }
18789a1d03eSRichard
escape_inside2()18889a1d03eSRichard void escape_inside2() {
18989a1d03eSRichard int i = 0;
19089a1d03eSRichard int Limit = 100;
19189a1d03eSRichard while (i < Limit) {
19289a1d03eSRichard // Not an error, since ii is alias of i.
19389a1d03eSRichard int &ii = i;
19489a1d03eSRichard ii++;
19589a1d03eSRichard }
19689a1d03eSRichard
19789a1d03eSRichard do {
19889a1d03eSRichard int &ii = i;
19989a1d03eSRichard ii++;
20089a1d03eSRichard } while (i < Limit);
20189a1d03eSRichard }
20289a1d03eSRichard
escape_after1()20389a1d03eSRichard void escape_after1() {
20489a1d03eSRichard int i = 0;
20589a1d03eSRichard int j = 0;
20689a1d03eSRichard int Limit = 10;
20789a1d03eSRichard
20889a1d03eSRichard while (i < Limit) {
20989a1d03eSRichard // False negative, but difficult to detect without CFG-based analysis
21089a1d03eSRichard }
21189a1d03eSRichard int *p = &i;
21289a1d03eSRichard }
21389a1d03eSRichard
escape_after2()21489a1d03eSRichard void escape_after2() {
21589a1d03eSRichard int i = 0;
21689a1d03eSRichard int j = 0;
21789a1d03eSRichard int Limit = 10;
21889a1d03eSRichard
21989a1d03eSRichard while (i < Limit) {
22089a1d03eSRichard // False negative, but difficult to detect without CFG-based analysis
22189a1d03eSRichard }
22289a1d03eSRichard int &ii = i;
22389a1d03eSRichard }
22489a1d03eSRichard
22589a1d03eSRichard int glob;
22689a1d03eSRichard
global1(int & x)22789a1d03eSRichard void global1(int &x) {
22889a1d03eSRichard int i = 0, Limit = 100;
22989a1d03eSRichard while (x < Limit) {
23089a1d03eSRichard // Not an error since 'x' can be an alias of 'glob'.
23189a1d03eSRichard glob++;
23289a1d03eSRichard }
23389a1d03eSRichard }
23489a1d03eSRichard
global2()23589a1d03eSRichard void global2() {
23689a1d03eSRichard int i = 0, Limit = 100;
23789a1d03eSRichard while (glob < Limit) {
23889a1d03eSRichard // Since 'glob' is declared out of the function we do not warn.
23989a1d03eSRichard i++;
24089a1d03eSRichard }
24189a1d03eSRichard }
24289a1d03eSRichard
24389a1d03eSRichard struct X {
24489a1d03eSRichard int m;
24589a1d03eSRichard
24689a1d03eSRichard void change_m();
24789a1d03eSRichard
member_expr1X24889a1d03eSRichard void member_expr1(int i) {
24989a1d03eSRichard while (i < m) {
25089a1d03eSRichard // False negative: No warning, since skipping the case where a struct or
25189a1d03eSRichard // class can be found in its condition.
25289a1d03eSRichard ;
25389a1d03eSRichard }
25489a1d03eSRichard }
25589a1d03eSRichard
member_expr2X25689a1d03eSRichard void member_expr2(int i) {
25789a1d03eSRichard while (i < m) {
25889a1d03eSRichard --m;
25989a1d03eSRichard }
26089a1d03eSRichard }
26189a1d03eSRichard
member_expr3X26289a1d03eSRichard void member_expr3(int i) {
26389a1d03eSRichard while (i < m) {
26489a1d03eSRichard change_m();
26589a1d03eSRichard }
26689a1d03eSRichard }
26789a1d03eSRichard };
26889a1d03eSRichard
array_index()26989a1d03eSRichard void array_index() {
27089a1d03eSRichard int i = 0;
27189a1d03eSRichard int v[10];
27289a1d03eSRichard while (i < 10) {
27389a1d03eSRichard v[i++] = 0;
27489a1d03eSRichard }
27589a1d03eSRichard
27689a1d03eSRichard i = 0;
27789a1d03eSRichard do {
27889a1d03eSRichard v[i++] = 0;
27989a1d03eSRichard } while (i < 9);
28089a1d03eSRichard
28189a1d03eSRichard for (i = 0; i < 10;) {
28289a1d03eSRichard v[i++] = 0;
28389a1d03eSRichard }
28489a1d03eSRichard
28589a1d03eSRichard for (i = 0; i < 10; v[i++] = 0) {
28689a1d03eSRichard }
28789a1d03eSRichard }
28889a1d03eSRichard
no_loop_variable()28989a1d03eSRichard void no_loop_variable() {
29089a1d03eSRichard while (0)
29189a1d03eSRichard ;
29289a1d03eSRichard }
29389a1d03eSRichard
volatile_in_condition()29489a1d03eSRichard void volatile_in_condition() {
29589a1d03eSRichard volatile int cond = 0;
29689a1d03eSRichard while (!cond) {
29789a1d03eSRichard }
29889a1d03eSRichard }
29989a1d03eSRichard
30089a1d03eSRichard namespace std {
30189a1d03eSRichard template<typename T> class atomic {
30289a1d03eSRichard T val;
30389a1d03eSRichard public:
atomic(T v)30489a1d03eSRichard atomic(T v): val(v) {};
operator T()30589a1d03eSRichard operator T() { return val; };
30689a1d03eSRichard };
30789a1d03eSRichard }
30889a1d03eSRichard
atomic_in_condition()30989a1d03eSRichard void atomic_in_condition() {
31089a1d03eSRichard std::atomic<int> cond = 0;
31189a1d03eSRichard while (!cond) {
31289a1d03eSRichard }
31389a1d03eSRichard }
31489a1d03eSRichard
loop_exit1()31589a1d03eSRichard void loop_exit1() {
31689a1d03eSRichard int i = 0;
31789a1d03eSRichard while (i) {
31889a1d03eSRichard if (unknown_function())
31989a1d03eSRichard break;
32089a1d03eSRichard }
32189a1d03eSRichard }
32289a1d03eSRichard
loop_exit2()32389a1d03eSRichard void loop_exit2() {
32489a1d03eSRichard int i = 0;
32589a1d03eSRichard while (i) {
32689a1d03eSRichard if (unknown_function())
32789a1d03eSRichard return;
32889a1d03eSRichard }
32989a1d03eSRichard }
33089a1d03eSRichard
loop_exit3()33189a1d03eSRichard void loop_exit3() {
33289a1d03eSRichard int i = 0;
33389a1d03eSRichard while (i) {
33489a1d03eSRichard if (unknown_function())
33589a1d03eSRichard goto end;
33689a1d03eSRichard }
33789a1d03eSRichard end:
33889a1d03eSRichard ;
33989a1d03eSRichard }
34089a1d03eSRichard
loop_exit4()34189a1d03eSRichard void loop_exit4() {
34289a1d03eSRichard int i = 0;
34389a1d03eSRichard while (i) {
34489a1d03eSRichard if (unknown_function())
34589a1d03eSRichard throw 1;
34689a1d03eSRichard }
34789a1d03eSRichard }
34889a1d03eSRichard
34989a1d03eSRichard [[noreturn]] void exit(int);
35089a1d03eSRichard
loop_exit5()35189a1d03eSRichard void loop_exit5() {
35289a1d03eSRichard int i = 0;
35389a1d03eSRichard while (i) {
35489a1d03eSRichard if (unknown_function())
35589a1d03eSRichard exit(1);
35689a1d03eSRichard }
35789a1d03eSRichard }
35889a1d03eSRichard
loop_exit_in_lambda()35989a1d03eSRichard void loop_exit_in_lambda() {
36089a1d03eSRichard int i = 0;
36189a1d03eSRichard while (i) {
36289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
36389a1d03eSRichard auto l = []() { return 0; };
36489a1d03eSRichard }
36589a1d03eSRichard }
36689a1d03eSRichard
lambda_capture()36789a1d03eSRichard void lambda_capture() {
36889a1d03eSRichard int i = 0;
36989a1d03eSRichard int Limit = 100;
37089a1d03eSRichard int *p = &i;
37189a1d03eSRichard while (i < Limit) {
37289a1d03eSRichard // Not an error, since i is captured by reference in a lambda.
37389a1d03eSRichard auto l = [&i]() { ++i; };
37489a1d03eSRichard }
37589a1d03eSRichard
37689a1d03eSRichard do {
37789a1d03eSRichard int *p = &i;
37889a1d03eSRichard (*p)++;
37989a1d03eSRichard } while (i < Limit);
38089a1d03eSRichard }
38189a1d03eSRichard
accept_callback(T t)38289a1d03eSRichard template <typename T> void accept_callback(T t) {
38389a1d03eSRichard // Potentially call the callback.
38489a1d03eSRichard // Possibly on a background thread or something.
38589a1d03eSRichard }
38689a1d03eSRichard
38789a1d03eSRichard void accept_block(void (^)(void)) {
38889a1d03eSRichard // Potentially call the callback.
38989a1d03eSRichard // Possibly on a background thread or something.
39089a1d03eSRichard }
39189a1d03eSRichard
wait(void)39289a1d03eSRichard void wait(void) {
39389a1d03eSRichard // Wait for the previously passed callback to be called.
39489a1d03eSRichard }
39589a1d03eSRichard
lambda_capture_from_outside()39689a1d03eSRichard void lambda_capture_from_outside() {
39789a1d03eSRichard bool finished = false;
39889a1d03eSRichard accept_callback([&]() {
39989a1d03eSRichard finished = true;
40089a1d03eSRichard });
40189a1d03eSRichard while (!finished) {
40289a1d03eSRichard wait();
40389a1d03eSRichard }
40489a1d03eSRichard }
40589a1d03eSRichard
lambda_capture_from_outside_by_value()40689a1d03eSRichard void lambda_capture_from_outside_by_value() {
40789a1d03eSRichard bool finished = false;
40889a1d03eSRichard accept_callback([finished]() {
40989a1d03eSRichard if (finished) {}
41089a1d03eSRichard });
41189a1d03eSRichard while (!finished) {
41289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
41389a1d03eSRichard wait();
41489a1d03eSRichard }
41589a1d03eSRichard }
41689a1d03eSRichard
lambda_capture_from_outside_but_unchanged()41789a1d03eSRichard void lambda_capture_from_outside_but_unchanged() {
41889a1d03eSRichard bool finished = false;
41989a1d03eSRichard accept_callback([&finished]() {
42089a1d03eSRichard if (finished) {}
42189a1d03eSRichard });
42289a1d03eSRichard while (!finished) {
42389a1d03eSRichard // FIXME: Should warn.
42489a1d03eSRichard wait();
42589a1d03eSRichard }
42689a1d03eSRichard }
42789a1d03eSRichard
block_capture_from_outside()42889a1d03eSRichard void block_capture_from_outside() {
42989a1d03eSRichard __block bool finished = false;
43089a1d03eSRichard accept_block(^{
43189a1d03eSRichard finished = true;
43289a1d03eSRichard });
43389a1d03eSRichard while (!finished) {
43489a1d03eSRichard wait();
43589a1d03eSRichard }
43689a1d03eSRichard }
43789a1d03eSRichard
block_capture_from_outside_by_value()43889a1d03eSRichard void block_capture_from_outside_by_value() {
43989a1d03eSRichard bool finished = false;
44089a1d03eSRichard accept_block(^{
44189a1d03eSRichard if (finished) {}
44289a1d03eSRichard });
44389a1d03eSRichard while (!finished) {
44489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
44589a1d03eSRichard wait();
44689a1d03eSRichard }
44789a1d03eSRichard }
44889a1d03eSRichard
block_capture_from_outside_but_unchanged()44989a1d03eSRichard void block_capture_from_outside_but_unchanged() {
45089a1d03eSRichard __block bool finished = false;
45189a1d03eSRichard accept_block(^{
45289a1d03eSRichard if (finished) {}
45389a1d03eSRichard });
45489a1d03eSRichard while (!finished) {
45589a1d03eSRichard // FIXME: Should warn.
45689a1d03eSRichard wait();
45789a1d03eSRichard }
45889a1d03eSRichard }
45989a1d03eSRichard
46089a1d03eSRichard void finish_at_any_time(bool *finished);
46189a1d03eSRichard
lambda_capture_with_loop_inside_lambda_bad()46289a1d03eSRichard void lambda_capture_with_loop_inside_lambda_bad() {
46389a1d03eSRichard bool finished = false;
46489a1d03eSRichard auto lambda = [=]() {
46589a1d03eSRichard while (!finished) {
46689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
46789a1d03eSRichard wait();
46889a1d03eSRichard }
46989a1d03eSRichard };
47089a1d03eSRichard finish_at_any_time(&finished);
47189a1d03eSRichard lambda();
47289a1d03eSRichard }
47389a1d03eSRichard
lambda_capture_with_loop_inside_lambda_bad_init_capture()47489a1d03eSRichard void lambda_capture_with_loop_inside_lambda_bad_init_capture() {
47589a1d03eSRichard bool finished = false;
47689a1d03eSRichard auto lambda = [captured_finished=finished]() {
47789a1d03eSRichard while (!captured_finished) {
47889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (captured_finished) are updated in the loop body [bugprone-infinite-loop]
47989a1d03eSRichard wait();
48089a1d03eSRichard }
48189a1d03eSRichard };
48289a1d03eSRichard finish_at_any_time(&finished);
48389a1d03eSRichard lambda();
48489a1d03eSRichard }
48589a1d03eSRichard
lambda_capture_with_loop_inside_lambda_good()48689a1d03eSRichard void lambda_capture_with_loop_inside_lambda_good() {
48789a1d03eSRichard bool finished = false;
48889a1d03eSRichard auto lambda = [&]() {
48989a1d03eSRichard while (!finished) {
49089a1d03eSRichard wait(); // No warning: the variable may be updated
49189a1d03eSRichard // from outside the lambda.
49289a1d03eSRichard }
49389a1d03eSRichard };
49489a1d03eSRichard finish_at_any_time(&finished);
49589a1d03eSRichard lambda();
49689a1d03eSRichard }
49789a1d03eSRichard
lambda_capture_with_loop_inside_lambda_good_init_capture()49889a1d03eSRichard void lambda_capture_with_loop_inside_lambda_good_init_capture() {
49989a1d03eSRichard bool finished = false;
50089a1d03eSRichard auto lambda = [&captured_finished=finished]() {
50189a1d03eSRichard while (!captured_finished) {
50289a1d03eSRichard wait(); // No warning: the variable may be updated
50389a1d03eSRichard // from outside the lambda.
50489a1d03eSRichard }
50589a1d03eSRichard };
50689a1d03eSRichard finish_at_any_time(&finished);
50789a1d03eSRichard lambda();
50889a1d03eSRichard }
50989a1d03eSRichard
block_capture_with_loop_inside_block_bad()51089a1d03eSRichard void block_capture_with_loop_inside_block_bad() {
51189a1d03eSRichard bool finished = false;
51289a1d03eSRichard auto block = ^() {
51389a1d03eSRichard while (!finished) {
51489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
51589a1d03eSRichard wait();
51689a1d03eSRichard }
51789a1d03eSRichard };
51889a1d03eSRichard finish_at_any_time(&finished);
51989a1d03eSRichard block();
52089a1d03eSRichard }
52189a1d03eSRichard
block_capture_with_loop_inside_block_bad_simpler()52289a1d03eSRichard void block_capture_with_loop_inside_block_bad_simpler() {
52389a1d03eSRichard bool finished = false;
52489a1d03eSRichard auto block = ^() {
52589a1d03eSRichard while (!finished) {
52689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop]
52789a1d03eSRichard wait();
52889a1d03eSRichard }
52989a1d03eSRichard };
53089a1d03eSRichard block();
53189a1d03eSRichard }
53289a1d03eSRichard
block_capture_with_loop_inside_block_good()53389a1d03eSRichard void block_capture_with_loop_inside_block_good() {
53489a1d03eSRichard __block bool finished = false;
53589a1d03eSRichard auto block = ^() {
53689a1d03eSRichard while (!finished) {
53789a1d03eSRichard wait(); // No warning: the variable may be updated
53889a1d03eSRichard // from outside the block.
53989a1d03eSRichard }
54089a1d03eSRichard };
54189a1d03eSRichard finish_at_any_time(&finished);
54289a1d03eSRichard block();
54389a1d03eSRichard }
54489a1d03eSRichard
evaluatable(bool CondVar)54589a1d03eSRichard void evaluatable(bool CondVar) {
54689a1d03eSRichard for (; false && CondVar;) {
54789a1d03eSRichard }
54889a1d03eSRichard while (false && CondVar) {
54989a1d03eSRichard }
55089a1d03eSRichard do {
55189a1d03eSRichard } while (false && CondVar);
55289a1d03eSRichard }
55389a1d03eSRichard
55489a1d03eSRichard struct logger {
55589a1d03eSRichard void (*debug)(struct logger *, const char *, ...);
55689a1d03eSRichard };
55789a1d03eSRichard
foo(void)55889a1d03eSRichard int foo(void) {
55989a1d03eSRichard struct logger *pl = 0;
56089a1d03eSRichard int iterator = 0;
56189a1d03eSRichard while (iterator < 10) {
56289a1d03eSRichard char *l_tmp_msg = 0;
56389a1d03eSRichard pl->debug(pl, "%d: %s\n", iterator, l_tmp_msg);
56489a1d03eSRichard iterator++;
56589a1d03eSRichard }
56689a1d03eSRichard return 0;
56789a1d03eSRichard }
56889a1d03eSRichard
56989a1d03eSRichard struct AggregateWithReference {
57089a1d03eSRichard int &y;
57189a1d03eSRichard };
57289a1d03eSRichard
test_structured_bindings_good()57389a1d03eSRichard void test_structured_bindings_good() {
57489a1d03eSRichard int x = 0;
57589a1d03eSRichard AggregateWithReference ref { x };
57689a1d03eSRichard auto &[y] = ref;
57789a1d03eSRichard for (; x < 10; ++y) {
57889a1d03eSRichard // No warning. The loop is finite because 'y' is a reference to 'x'.
57989a1d03eSRichard }
58089a1d03eSRichard }
58189a1d03eSRichard
58289a1d03eSRichard struct AggregateWithValue {
58389a1d03eSRichard int y;
58489a1d03eSRichard };
58589a1d03eSRichard
test_structured_bindings_bad()58689a1d03eSRichard void test_structured_bindings_bad() {
58789a1d03eSRichard int x = 0;
58889a1d03eSRichard AggregateWithValue val { x };
58989a1d03eSRichard auto &[y] = val;
59089a1d03eSRichard for (; x < 10; ++y) {
59189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (x) are updated in the loop body [bugprone-infinite-loop]
59289a1d03eSRichard }
59389a1d03eSRichard }
59489a1d03eSRichard
test_volatile_cast()59589a1d03eSRichard void test_volatile_cast() {
59689a1d03eSRichard // This is a no-op cast. Clang ignores the qualifier, we should too.
59789a1d03eSRichard for (int i = 0; (volatile int)i < 10;) {
59889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
59989a1d03eSRichard }
60089a1d03eSRichard }
60189a1d03eSRichard
test_volatile_concrete_address(int i,int size)60289a1d03eSRichard void test_volatile_concrete_address(int i, int size) {
60389a1d03eSRichard // No warning. The value behind the volatile concrete address
60489a1d03eSRichard // is beyond our control. It may change at any time.
60589a1d03eSRichard for (; *((volatile int *)0x1234) < size;) {
60689a1d03eSRichard }
60789a1d03eSRichard
60889a1d03eSRichard for (; *((volatile int *)(0x1234 + i)) < size;) {
60989a1d03eSRichard }
61089a1d03eSRichard
61189a1d03eSRichard for (; **((volatile int **)0x1234) < size;) {
61289a1d03eSRichard }
61389a1d03eSRichard
61489a1d03eSRichard volatile int *x = (volatile int *)0x1234;
61589a1d03eSRichard for (; *x < 10;) {
61689a1d03eSRichard }
61789a1d03eSRichard
61889a1d03eSRichard // FIXME: This one should probably also be suppressed.
61989a1d03eSRichard // Whatever the developer is doing here, they can do that again anywhere else
62089a1d03eSRichard // which basically makes it a global.
62189a1d03eSRichard for (; *(int *)0x1234 < size;) {
62289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
62389a1d03eSRichard }
62489a1d03eSRichard }
62589a1d03eSRichard
62689a1d03eSRichard template <typename T>
some_template_fn()62789a1d03eSRichard int some_template_fn() { return 1; }
62889a1d03eSRichard
62989a1d03eSRichard template <typename T>
test_dependent_condition()63089a1d03eSRichard void test_dependent_condition() {
63189a1d03eSRichard const int error = some_template_fn<T>();
63289a1d03eSRichard do {
63389a1d03eSRichard } while (false && error == 0);
63489a1d03eSRichard
63589a1d03eSRichard const int val = some_template_fn<T>();
63689a1d03eSRichard for (; !(val == 0 || true);) {
63789a1d03eSRichard }
63889a1d03eSRichard
63989a1d03eSRichard const int val2 = some_template_fn<T>();
64089a1d03eSRichard for (; !(val2 == 0 || false);) {
64189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val2) are updated in the loop body [bugprone-infinite-loop]
64289a1d03eSRichard }
64389a1d03eSRichard
64489a1d03eSRichard const int val3 = some_template_fn<T>();
64589a1d03eSRichard do {
64689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val3) are updated in the loop body [bugprone-infinite-loop]
64789a1d03eSRichard } while (1, (true) && val3 == 1);
64889a1d03eSRichard
64989a1d03eSRichard const int val4 = some_template_fn<T>();
65089a1d03eSRichard do {
65189a1d03eSRichard } while (1, (false) && val4 == 1);
65289a1d03eSRichard }
65389a1d03eSRichard
test_typeof()65489a1d03eSRichard void test_typeof() {
65589a1d03eSRichard __typeof__({
65689a1d03eSRichard for (int i = 0; i < 10; ++i) {
65789a1d03eSRichard }
65889a1d03eSRichard 0;
65989a1d03eSRichard }) x;
66089a1d03eSRichard }
66189a1d03eSRichard
test_typeof_infinite()66289a1d03eSRichard void test_typeof_infinite() {
66389a1d03eSRichard __typeof__({
66489a1d03eSRichard for (int i = 0; i < 10;) {
66589a1d03eSRichard }
66689a1d03eSRichard 0;
66789a1d03eSRichard }) x;
66889a1d03eSRichard }
66989a1d03eSRichard
test_typeof_while_infinite()67089a1d03eSRichard void test_typeof_while_infinite() {
67189a1d03eSRichard __typeof__({
67289a1d03eSRichard int i = 0;
67389a1d03eSRichard while (i < 10) {
67489a1d03eSRichard }
67589a1d03eSRichard 0;
67689a1d03eSRichard }) x;
67789a1d03eSRichard }
67889a1d03eSRichard
test_typeof_dowhile_infinite()67989a1d03eSRichard void test_typeof_dowhile_infinite() {
68089a1d03eSRichard __typeof__({
68189a1d03eSRichard int i = 0;
68289a1d03eSRichard do {
68389a1d03eSRichard
68489a1d03eSRichard } while (i < 10);
68589a1d03eSRichard 0;
68689a1d03eSRichard }) x;
68789a1d03eSRichard }
688*7df0f0b4Sziqingluo-90
test_local_static_recursion()689*7df0f0b4Sziqingluo-90 void test_local_static_recursion() {
690*7df0f0b4Sziqingluo-90 static int i = 10;
691*7df0f0b4Sziqingluo-90 int j = 0;
692*7df0f0b4Sziqingluo-90
693*7df0f0b4Sziqingluo-90 i--;
694*7df0f0b4Sziqingluo-90 while (i >= 0)
695*7df0f0b4Sziqingluo-90 test_local_static_recursion(); // no warning, recursively decrement i
696*7df0f0b4Sziqingluo-90 for (; i >= 0;)
697*7df0f0b4Sziqingluo-90 test_local_static_recursion(); // no warning, recursively decrement i
698*7df0f0b4Sziqingluo-90 for (; i + j >= 0;)
699*7df0f0b4Sziqingluo-90 test_local_static_recursion(); // no warning, recursively decrement i
700*7df0f0b4Sziqingluo-90 for (; i >= 0; i--)
701*7df0f0b4Sziqingluo-90 ; // no warning, i decrements
702*7df0f0b4Sziqingluo-90 while (j >= 0)
703*7df0f0b4Sziqingluo-90 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (j) are updated in the loop body [bugprone-infinite-loop]
704*7df0f0b4Sziqingluo-90 test_local_static_recursion();
705*7df0f0b4Sziqingluo-90
706*7df0f0b4Sziqingluo-90 int (*p)(int) = 0;
707*7df0f0b4Sziqingluo-90
708*7df0f0b4Sziqingluo-90 while (i >= 0)
709*7df0f0b4Sziqingluo-90 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
710*7df0f0b4Sziqingluo-90 p = 0;
711*7df0f0b4Sziqingluo-90 while (i >= 0)
712*7df0f0b4Sziqingluo-90 p(0); // we don't know what p points to so no warning
713*7df0f0b4Sziqingluo-90 }
714