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,8 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+
+void foo() {}
+static void f2() {} 
+static void f1() {f2();} // expected-warning{{unused}}
+
+static int f0() { return 17; }
+int x = sizeof(f0());
\ No newline at end of file
Index: include/clang/Frontend/PCHBitCodes.h
===================================================================
--- include/clang/Frontend/PCHBitCodes.h	(revision 94579)
+++ include/clang/Frontend/PCHBitCodes.h	(working copy)
@@ -221,7 +221,11 @@
       
       /// \brief Record code for the version control branch and revision
       /// information of the compiler used to build this PCH file.
-      VERSION_CONTROL_BRANCH_REVISION = 21
+      VERSION_CONTROL_BRANCH_REVISION = 21,
+      
+      /// \brief Record code for the array of unused static functions.
+      UNUSED_STATIC_FUNCS = 22
+      
     };
 
     /// \brief Record types used within a source manager block.
Index: include/clang/Frontend/PCHReader.h
===================================================================
--- include/clang/Frontend/PCHReader.h	(revision 94579)
+++ include/clang/Frontend/PCHReader.h	(working copy)
@@ -306,6 +306,10 @@
   /// \brief The set of tentative definitions stored in the the PCH
   /// file.
   llvm::SmallVector<uint64_t, 16> TentativeDefinitions;
+      
+  /// \brief The set of tentative definitions stored in the the PCH
+  /// file.
+  llvm::SmallVector<uint64_t, 16> UnusedStaticFuncs;
 
   /// \brief The set of locally-scoped external declarations stored in
   /// the the PCH file.
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/Frontend/PCHWriter.cpp
===================================================================
--- lib/Frontend/PCHWriter.cpp	(revision 94579)
+++ lib/Frontend/PCHWriter.cpp	(working copy)
@@ -534,6 +534,7 @@
   RECORD(SPECIAL_TYPES);
   RECORD(STATISTICS);
   RECORD(TENTATIVE_DEFINITIONS);
+  RECORD(UNUSED_STATIC_FUNCS);
   RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
   RECORD(SELECTOR_OFFSETS);
   RECORD(METHOD_POOL);
@@ -1969,6 +1970,11 @@
     if (VD) AddDeclRef(VD, TentativeDefinitions);
   }
 
+  // Build a record containing all of the static unused functions in this file.
+  RecordData UnusedStaticFuncs;
+  for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) 
+    AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs);
+              
   // Build a record containing all of the locally-scoped external
   // declarations in this header file. Generally, this record will be
   // empty.
@@ -2070,6 +2076,10 @@
   if (!TentativeDefinitions.empty())
     Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
 
+  // Write the record containing unused static functions.
+  if (!UnusedStaticFuncs.empty())
+    Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs);
+  
   // Write the record containing locally-scoped external definitions.
   if (!LocallyScopedExternalDecls.empty())
     Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
Index: lib/Frontend/PCHReader.cpp
===================================================================
--- lib/Frontend/PCHReader.cpp	(revision 94579)
+++ lib/Frontend/PCHReader.cpp	(working copy)
@@ -1326,6 +1326,14 @@
       TentativeDefinitions.swap(Record);
       break;
 
+    case pch::UNUSED_STATIC_FUNCS:
+      if (!UnusedStaticFuncs.empty()) {
+        Error("duplicate UNUSED_STATIC_FUNCS record in PCH file");
+        return Failure;
+      }
+      UnusedStaticFuncs.swap(Record);
+      break;
+        
     case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
       if (!LocallyScopedExternalDecls.empty()) {
         Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
@@ -2470,6 +2478,13 @@
     SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
     SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
   }
+  
+  // If there were any unused static functions, deserialize them and add to
+  // Seam's list of unused static functions.
+  for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) {
+    FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I]));
+    SemaObj->UnusedStaticFuncs.push_back(FD);
+  }
 
   // If there were any locally-scoped external declarations,
   // deserialize them and add them to Sema's table of locally-scoped
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 94579)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -3063,6 +3063,14 @@
   if (FunctionTemplate)
     return FunctionTemplate;
 
+  
+  // Keep track of static, non-inlined function definitions that
+  // have not been used. We will warn later.
+  if (!NewFD->isInvalidDecl() && IsFunctionDefinition 
+      && !isInline && SC == FunctionDecl::Static
+      && !NewFD->isUsed())
+    UnusedStaticFuncs.push_back(NewFD);
+  
   return NewFD;
 }
 
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 94579)
+++ lib/Sema/Sema.h	(working copy)
@@ -280,6 +280,9 @@
   llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
   std::vector<DeclarationName> TentativeDefinitionList;
 
+  /// \brief The set of static functions seen so far that have not been used.
+  std::vector<FunctionDecl*> UnusedStaticFuncs;
+  
   /// \brief The collection of delayed deprecation warnings.
   llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8>
     DelayedDeprecationWarnings;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 94579)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -7244,6 +7244,17 @@
     
     // FIXME: keep track of references to static functions
     Function->setUsed(true);
+   
+    // Remove used function from our list of static unused functions to prevent
+    // the unused function warning from triggering.
+    if (Function->getStorageClass() == FunctionDecl::Static) {
+      std::vector<FunctionDecl*>::iterator I = std::find(UnusedStaticFuncs.begin(),
+                                                         UnusedStaticFuncs.end(),
+                                                         Function);
+      if (I != UnusedStaticFuncs.end())
+        UnusedStaticFuncs.erase(I);
+    }
+    
     return;
   }
 
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 94579)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -504,6 +504,15 @@
       Consumer.CompleteTentativeDefinition(VD);
 
   }
+  
+  // Output warning for unused functions.
+  for (std::vector<FunctionDecl*>::iterator
+       F = UnusedStaticFuncs.begin(),
+       FEnd = UnusedStaticFuncs.end();
+       F != FEnd;
+       ++F)
+    Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName();
+  
 }
 
 
