Index: test/Sema/warn-unused-function.c
===================================================================
--- test/Sema/warn-unused-function.c	(revision 0)
+++ test/Sema/warn-unused-function.c	(revision 0)
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+
+void foo() {}
+
+static void f1() {} // expected-warning{{unused}}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 94579)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -85,6 +85,8 @@
   InGroup<UnusedVariable>, DefaultIgnore;
 def warn_decl_in_param_list : Warning<
   "declaration of %0 will not be visible outside of this function">;
+def warn_unused_function : Warning<"unused function %0">,
+  InGroup<UnusedFunction>, DefaultIgnore;
 
 def warn_implicit_function_decl : Warning<
   "implicit declaration of function %0">,
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 94579)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -504,6 +504,21 @@
       Consumer.CompleteTentativeDefinition(VD);
 
   }
+  
+  for (DeclContext::decl_iterator
+       D = Context.getTranslationUnitDecl()->decls_begin(),
+       DEnd = Context.getTranslationUnitDecl()->decls_end();
+       D != DEnd;
+       ++D) {
+    // Check for unused functions.
+    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
+      if (!FD->isUsed() && !FD->hasAttr<UnusedAttr>()
+          && (FD->getStorageClass() == FunctionDecl::Static)) {
+        Diag(FD->getLocation(), diag::warn_unused_function) << FD->getDeclName();
+      }
+    }
+  }
+  
 }
 
 
