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}}
 |