xref: /llvm-project/clang/test/SemaCXX/warn-infinite-recursion.cpp (revision 97608445b12e93b95111031492d8a46a97f33db3)
1 // RUN: %clang_cc1 %s -fsyntax-only -verify -Winfinite-recursion
2 
3 void a() {  // expected-warning{{call itself}}
4   a();
5 }
6 
7 void b(int x) {  // expected-warning{{call itself}}
8   if (x)
9     b(x);
10   else
11     b(x+1);
12 }
13 
14 void c(int x) {
15   if (x)
16     c(5);
17 }
18 
19 void d(int x) {  // expected-warning{{call itself}}
20   if (x)
21     ++x;
22   return d(x);
23 }
24 
25 // Doesn't warn on mutually recursive functions
26 void e();
27 void f();
28 
29 void e() { f(); }
30 void f() { e(); }
31 
32 void g() {  // expected-warning{{call itself}}
33   while (true)
34     g();
35 
36   g();
37 }
38 
39 void h(int x) {
40   while (x < 5) {
41     h(x+1);
42   }
43 }
44 
45 void i(int x) {  // expected-warning{{call itself}}
46   while (x < 5) {
47     --x;
48   }
49   i(0);
50 }
51 
52 int j() {  // expected-warning{{call itself}}
53   return 5 + j();
54 }
55 
56 void k() {  // expected-warning{{call itself}}
57   while(true) {
58     k();
59   }
60 }
61 
62 // Don't warn on infinite loops
63 void l() {
64   while (true) {}
65 
66   l();
67 }
68 
69 class S {
70   static void a();
71   void b();
72 };
73 
74 void S::a() {  // expected-warning{{call itself}}
75   return a();
76 }
77 
78 void S::b() {  // expected-warning{{call itself}}
79   int i = 0;
80   do {
81     ++i;
82     b();
83   } while (i > 5);
84 }
85 
86 template<class member>
87 struct T {
88   member m;
89   void a() { return a(); }  // expected-warning{{call itself}}
90   static void b() { return b(); }  // expected-warning{{call itself}}
91 };
92 
93 void test_T() {
94   T<int> foo;
95   foo.a();  // expected-note{{in instantiation}}
96   foo.b();  // expected-note{{in instantiation}}
97 }
98 
99 class U {
100   U* u;
101   void Fun() {  // expected-warning{{call itself}}
102     u->Fun();
103   }
104 };
105 
106 // No warnings on templated functions
107 // sum<0>() is instantiated, does recursively call itself, but never runs.
108 template <int value>
109 int sum() {
110   return value + sum<value/2>();
111 }
112 
113 template<>
114 int sum<1>() { return 1; }
115 
116 template<int x, int y>
117 int calculate_value() {
118   if (x != y)
119     return sum<x - y>();  // This instantiates sum<0>() even if never called.
120   else
121     return 0;
122 }
123 
124 int value = calculate_value<1,1>();
125 
126 void DoSomethingHere();
127 
128 // DoStuff<0,0>() is instantiated, but never called.
129 template<int First, int Last>
130 int DoStuff() {
131   if (First + 1 == Last) {
132     // This branch gets removed during <0, 0> instantiation in so CFG for this
133     // function goes straight to the else branch.
134     DoSomethingHere();
135   } else {
136     DoStuff<First, (First + Last)/2>();
137     DoStuff<(First + Last)/2, Last>();
138   }
139   return 0;
140 }
141 int stuff = DoStuff<0, 1>();
142 
143 template<int x>
144 struct Wrapper {
145   static int run() {
146     // Similar to the above, Wrapper<0>::run() will discard the if statement.
147     if (x == 1)
148       return 0;
149     return Wrapper<x/2>::run();
150   }
151   static int run2() {  // expected-warning{{call itself}}
152     return run2();
153   }
154 };
155 
156 template <int x>
157 int test_wrapper() {
158   if (x != 0)
159     return Wrapper<x>::run() +
160            Wrapper<x>::run2();  // expected-note{{instantiation}}
161   return 0;
162 }
163 
164 int wrapper_sum = test_wrapper<2>();  // expected-note{{instantiation}}
165