blob: bbeff92a657b8f8fe0672857bc1437b7884e470b [file] [log] [blame]
// 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(); }
void g() { // expected-warning{{call itself}}
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();
}
void k() { // expected-warning{{call itself}}
while(true) {
k();
}
}
// Don't warn on infinite loops
void l() {
while (true) {}
l();
}
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}}