From e6bbc01d1c4ec5241df36042e0a4a12a6711934b Mon Sep 17 00:00:00 2001 From: Tanya Lattner Date: Fri, 12 Feb 2010 00:07:30 +0000 Subject: [PATCH] Implementing unused function warning. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95940 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 +++- include/clang/Frontend/PCHBitCodes.h | 6 +++++- include/clang/Frontend/PCHReader.h | 4 ++++ lib/Frontend/PCHReader.cpp | 15 +++++++++++++++ lib/Frontend/PCHWriter.cpp | 10 ++++++++++ lib/Sema/Sema.cpp | 15 +++++++++++++++ lib/Sema/Sema.h | 3 +++ lib/Sema/SemaDecl.cpp | 9 +++++++++ lib/Sema/SemaExpr.cpp | 1 + test/Sema/warn-unused-function.c | 16 ++++++++++++++++ 10 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 test/Sema/warn-unused-function.c diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index af861ff96f..0eb694cb91 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -87,7 +87,9 @@ def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">; def err_array_star_in_function_definition : Error< "variable length array must be bound in function definition">; - +def warn_unused_function : Warning<"unused function %0">, + InGroup, DefaultIgnore; + def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup, DefaultIgnore; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 578ce2a9e1..e22d37ba34 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -221,7 +221,11 @@ namespace clang { /// \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. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 9665ce189f..065006fce5 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -306,6 +306,10 @@ private: /// \brief The set of tentative definitions stored in the the PCH /// file. llvm::SmallVector TentativeDefinitions; + + /// \brief The set of tentative definitions stored in the the PCH + /// file. + llvm::SmallVector UnusedStaticFuncs; /// \brief The set of locally-scoped external declarations stored in /// the the PCH file. diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 2a22132ea8..f6f4a78c13 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1332,6 +1332,14 @@ PCHReader::ReadPCHBlock() { 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"); @@ -2479,6 +2487,13 @@ void PCHReader::InitializeSema(Sema &S) { VarDecl *Var = cast(GetDecl(TentativeDefinitions[I])); SemaObj->TentativeDefinitions.push_back(Var); } + + // If there were any unused static functions, deserialize them and add to + // Sema's list of unused static functions. + for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) { + FunctionDecl *FD = cast(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 diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index c7e6058d65..4c99dbe245 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -545,6 +545,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); + RECORD(UNUSED_STATIC_FUNCS); RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); @@ -1982,6 +1983,11 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddDeclRef(SemaRef.TentativeDefinitions[i], 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. @@ -2083,6 +2089,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, 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, diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e9a1d9c5fc..38c842eede 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -185,6 +185,12 @@ void Sema::DeleteStmt(StmtTy *S) { /// popped. void Sema::ActOnEndOfTranslationUnit() { + // Remove functions that turned out to be used. + UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), + UnusedStaticFuncs.end(), + std::mem_fun(&FunctionDecl::isUsed)), + UnusedStaticFuncs.end()); + while (1) { // C++: Perform implicit template instantiations. // @@ -265,6 +271,15 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } + + // Output warning for unused functions. + for (std::vector::iterator + F = UnusedStaticFuncs.begin(), + FEnd = UnusedStaticFuncs.end(); + F != FEnd; + ++F) + Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName(); + } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a835c477e2..0ee16cae95 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -276,6 +276,9 @@ public: /// \brief All the tentative definitions encountered in the TU. std::vector TentativeDefinitions; + /// \brief The set of static functions seen so far that have not been used. + std::vector UnusedStaticFuncs; + /// An enum describing the kind of diagnostics to use when checking /// access. enum AccessDiagnosticsKind { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e6b047a959..feb9f8511c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3129,6 +3129,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; + + // Keep track of static, non-inlined function definitions that + // have not been used. We will warn later. + // FIXME: Also include static functions declared but not defined. + if (!NewFD->isInvalidDecl() && IsFunctionDefinition + && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage + && !NewFD->isUsed()) + UnusedStaticFuncs.push_back(NewFD); + return NewFD; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0563428b18..940c3d3e7f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7293,6 +7293,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // FIXME: keep track of references to static functions Function->setUsed(true); + return; } diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c new file mode 100644 index 0000000000..178527f01c --- /dev/null +++ b/test/Sema/warn-unused-function.c @@ -0,0 +1,16 @@ +// 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; } // expected-warning{{unused}} +int x = sizeof(f0()); + +static void f3(); +extern void f3() { } // expected-warning{{unused}} + +// FIXME: This will trigger a warning when it should not. +// Update once PR6281 is fixed. +//inline static void f4(); +//void f4() { } \ No newline at end of file -- 2.40.0