Add -Winfinite-recursion to Clang
This new warning detects when a function will recursively call itself on every
code path though that function. This catches simple recursive cases such as:
void foo() {
foo();
}
As well as more complex functions like:
void bar() {
if (test()) {
bar();
return;
} else {
bar();
}
return;
}
This warning uses the CFG. As with other CFG-based warnings, this is off
by default. Due to false positives, this warning is also disabled for
templated functions.
llvm-svn: 197853
diff --git a/clang/test/SemaCXX/warn-infinite-recursion.cpp b/clang/test/SemaCXX/warn-infinite-recursion.cpp
new file mode 100644
index 0000000..088d4ba
--- /dev/null
+++ b/clang/test/SemaCXX/warn-infinite-recursion.cpp
@@ -0,0 +1,129 @@
+// 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>();