174 lines
2.9 KiB
C++
174 lines
2.9 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(); }
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
// Don't warn on infinite loops
|
||
|
void k() {
|
||
|
while(true) {
|
||
|
k();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void l() {
|
||
|
while (true) {}
|
||
|
|
||
|
l();
|
||
|
}
|
||
|
|
||
|
void m() {
|
||
|
static int count = 5;
|
||
|
if (count >0) {
|
||
|
count--;
|
||
|
l();
|
||
|
}
|
||
|
while (true) {}
|
||
|
}
|
||
|
|
||
|
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}}
|