153 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_cc1 %s -fsyntax-only -verify -Winfinite-recursion
 | |
| 
 | |
| void a() {  // expected-warning{{call itself}}
 | |
|   a();
 | |
| }
 | |
| 
 | |
| void b(int x) {  // expected-warning{{call itself}}
 | |
|   if (x)
 | |
|     b(x);
 | |
|   else
 | |
|     b(x+1);
 | |
| }
 | |
| 
 | |
| void c(int x) {
 | |
|   if (x)
 | |
|     c(5);
 | |
| }
 | |
| 
 | |
| void d(int x) {  // expected-warning{{call itself}}
 | |
|   if (x)
 | |
|     ++x;
 | |
|   return d(x);
 | |
| }
 | |
| 
 | |
| // Doesn't warn on mutually recursive functions
 | |
| void e();
 | |
| void f();
 | |
| 
 | |
| void e() { f(); }
 | |
| void f() { e(); }
 | |
| 
 | |
| // Don't warn on infinite loops
 | |
| void g() {
 | |
|   while (true)
 | |
|     g();
 | |
| 
 | |
|   g();
 | |
| }
 | |
| 
 | |
| void h(int x) {
 | |
|   while (x < 5) {
 | |
|     h(x+1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void i(int x) {  // expected-warning{{call itself}}
 | |
|   while (x < 5) {
 | |
|     --x;
 | |
|   }
 | |
|   i(0);
 | |
| }
 | |
| 
 | |
| int j() {  // expected-warning{{call itself}}
 | |
|   return 5 + j();
 | |
| }
 | |
| 
 | |
| class S {
 | |
|   static void a();
 | |
|   void b();
 | |
| };
 | |
| 
 | |
| void S::a() {  // expected-warning{{call itself}}
 | |
|   return a();
 | |
| }
 | |
| 
 | |
| void S::b() {  // expected-warning{{call itself}}
 | |
|   int i = 0;
 | |
|   do {
 | |
|     ++i;
 | |
|     b();
 | |
|   } while (i > 5);
 | |
| }
 | |
| 
 | |
| template<class member>
 | |
| struct T {
 | |
|   member m;
 | |
|   void a() { return a(); }  // expected-warning{{call itself}}
 | |
|   static void b() { return b(); }  // expected-warning{{call itself}}
 | |
| };
 | |
| 
 | |
| void test_T() {
 | |
|   T<int> foo;
 | |
|   foo.a();  // expected-note{{in instantiation}}
 | |
|   foo.b();  // expected-note{{in instantiation}}
 | |
| }
 | |
| 
 | |
| class U {
 | |
|   U* u;
 | |
|   void Fun() {  // expected-warning{{call itself}}
 | |
|     u->Fun();
 | |
|   }
 | |
| };
 | |
| 
 | |
| // No warnings on templated functions
 | |
| // sum<0>() is instantiated, does recursively call itself, but never runs.
 | |
| template <int value>
 | |
| int sum() {
 | |
|   return value + sum<value/2>();
 | |
| }
 | |
| 
 | |
| template<>
 | |
| int sum<1>() { return 1; }
 | |
| 
 | |
| template<int x, int y>
 | |
| int calculate_value() {
 | |
|   if (x != y)
 | |
|     return sum<x - y>();  // This instantiates sum<0>() even if never called.
 | |
|   else
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int value = calculate_value<1,1>();
 | |
| 
 | |
| void DoSomethingHere();
 | |
| 
 | |
| // DoStuff<0,0>() is instantiated, but never called.
 | |
| template<int First, int Last>
 | |
| int DoStuff() {
 | |
|   if (First + 1 == Last) {
 | |
|     // This branch gets removed during <0, 0> instantiation in so CFG for this
 | |
|     // function goes straight to the else branch.
 | |
|     DoSomethingHere();
 | |
|   } else {
 | |
|     DoStuff<First, (First + Last)/2>();
 | |
|     DoStuff<(First + Last)/2, Last>();
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| int stuff = DoStuff<0, 1>();
 | |
| 
 | |
| template<int x>
 | |
| struct Wrapper {
 | |
|   static int run() {
 | |
|     // Similar to the above, Wrapper<0>::run() will discard the if statement.
 | |
|     if (x == 1)
 | |
|       return 0;
 | |
|     return Wrapper<x/2>::run();
 | |
|   }
 | |
|   static int run2() {  // expected-warning{{call itself}}
 | |
|     return run2();
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <int x>
 | |
| int test_wrapper() {
 | |
|   if (x != 0)
 | |
|     return Wrapper<x>::run() +
 | |
|            Wrapper<x>::run2();  // expected-note{{instantiation}}
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int wrapper_sum = test_wrapper<2>();  // expected-note{{instantiation}}
 |