diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-08-13 18:42:29 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-08-13 18:42:29 +0000 |
commit | 540bc01f500e353d3233edb799b1b5d868633c48 (patch) | |
tree | 1d84c58136922739a7fe41e2443c10da8e781630 /clang | |
parent | 35672e78523162ab292962ce5aec3f512ee5cf8a (diff) | |
download | bcm5719-llvm-540bc01f500e353d3233edb799b1b5d868633c48.tar.gz bcm5719-llvm-540bc01f500e353d3233edb799b1b5d868633c48.zip |
Expand the unused warnings for functions. Warn for:
-static function declarations
-functions in anonymous namespace
-class methods in anonymous namespace
-class method specializations in anonymous namespace
-function specializations in anonymous namespace
llvm-svn: 111026
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 4 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 50 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 | ||||
-rw-r--r-- | clang/test/Sema/warn-unused-function.c | 9 | ||||
-rw-r--r-- | clang/test/SemaCXX/warn-unused-filescoped.cpp | 27 |
6 files changed, 104 insertions, 26 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d2b89824a79..31c63705fda 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -349,7 +349,8 @@ public: std::vector<VarDecl *> TentativeDefinitions; /// \brief The set of file scoped decls seen so far that have not been used - /// and must warn if not used. + /// and must warn if not used. For functions only contains the first + /// declaration. std::vector<const DeclaratorDecl*> UnusedFileScopedDecls; class AccessedEntity { @@ -1877,6 +1878,7 @@ public: MultiStmtArg Handlers); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index f5c85ad99cd..76e059138e6 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -235,6 +235,24 @@ void Sema::DeleteExpr(ExprTy *E) { void Sema::DeleteStmt(StmtTy *S) { } +/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. +static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { + if (D->isUsed()) + return true; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // For functions, UnusedFileScopedDecls stores the first declaration. + // Later redecls may add new information resulting in not having to warn, + // so check again. + const FunctionDecl *DeclToCheck; + if (!FD->hasBody(DeclToCheck)) + DeclToCheck = FD->getMostRecentDeclaration(); + if (DeclToCheck != FD) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + } + return false; +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. @@ -263,10 +281,10 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), - UnusedFileScopedDecls.end(), - std::bind2nd(std::mem_fun(&DeclaratorDecl::isUsed), - true)), + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.end(), + std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), + this)), UnusedFileScopedDecls.end()); if (!CompleteTranslationUnit) @@ -334,9 +352,13 @@ void Sema::ActOnEndOfTranslationUnit() { for (std::vector<const DeclaratorDecl*>::iterator I = UnusedFileScopedDecls.begin(), E = UnusedFileScopedDecls.end(); I != E; ++I) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) - Diag(FD->getLocation(), diag::warn_unused_function) << FD->getDeclName(); - else + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + const FunctionDecl *DiagD; + if (!FD->hasBody(DiagD)) + DiagD = FD; + Diag(DiagD->getLocation(), diag::warn_unused_function) + << DiagD->getDeclName(); + } else Diag((*I)->getLocation(), diag::warn_unused_variable) << cast<VarDecl>(*I)->getDeclName(); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e1f9c82feca..cf6f20f60ae 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -521,25 +521,40 @@ static void RemoveUsingDecls(LookupResult &R) { F.done(); } -static bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) { +bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { + assert(D); + if (D->isInvalidDecl() || D->isUsed() || D->hasAttr<UnusedAttr>()) + return false; + if (D->getLinkage() == ExternalLinkage) + return false; + + // Ignore class templates. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) + if (MD->getParent()->getDescribedClassTemplate()) + return false; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isThisDeclarationADefinition()) + return !Context.DeclMustBeEmitted(FD); + return true; + } + + return false; + } + + void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { + if (!D) + return; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Warn for static, non-inlined function definitions that - // have not been used. - // FIXME: Also include static functions declared but not defined. - return (!FD->isInvalidDecl() - && !FD->isInlined() && FD->getLinkage() == InternalLinkage - && !FD->isUsed() && !FD->hasAttr<UnusedAttr>() - && !FD->hasAttr<ConstructorAttr>() - && !FD->hasAttr<DestructorAttr>()); + const FunctionDecl *First = FD->getFirstDeclaration(); + if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) + return; // First should already be in the vector. } - - return false; -} -void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { - if (ShouldWarnIfUnusedFileScopedDecl(D)) - UnusedFileScopedDecls.push_back(D); -} + if (ShouldWarnIfUnusedFileScopedDecl(D)) + UnusedFileScopedDecls.push_back(D); + } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) @@ -3638,8 +3653,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; - if (IsFunctionDefinition) - MarkUnusedFileScopedDecl(NewFD); + MarkUnusedFileScopedDecl(NewFD); return NewFD; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index fd630f2ef3e..a48f1e06b83 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1204,6 +1204,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); + SemaRef.MarkUnusedFileScopedDecl(Function); + return Function; } @@ -1415,6 +1417,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, else Owner->addDecl(DeclToAdd); } + + SemaRef.MarkUnusedFileScopedDecl(Method); return Method; } diff --git a/clang/test/Sema/warn-unused-function.c b/clang/test/Sema/warn-unused-function.c index d5e676b1160..5ae0cce0798 100644 --- a/clang/test/Sema/warn-unused-function.c +++ b/clang/test/Sema/warn-unused-function.c @@ -35,3 +35,12 @@ void bar2(void) { } __attribute__((destructor)) static void bar3(void); void bar3(void) { } + +static void f10(void); // expected-warning{{unused}} +static void f10(void); + +static void f11(void); +static void f11(void) { } // expected-warning{{unused}} + +static void f12(void) { } // expected-warning{{unused}} +static void f12(void); diff --git a/clang/test/SemaCXX/warn-unused-filescoped.cpp b/clang/test/SemaCXX/warn-unused-filescoped.cpp new file mode 100644 index 00000000000..0ad23627797 --- /dev/null +++ b/clang/test/SemaCXX/warn-unused-filescoped.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s + +static void f1(); // expected-warning{{unused}} + +namespace { + void f2(); // expected-warning{{unused}} + + void f3() { } // expected-warning{{unused}} + + struct S { + void m1() { } // expected-warning{{unused}} + void m2(); // expected-warning{{unused}} + void m3(); + }; + + template <typename T> + struct TS { + void m(); + }; + template <> void TS<int>::m() { } // expected-warning{{unused}} + + template <typename T> + void tf() { } + template <> void tf<int>() { } // expected-warning{{unused}} +} + +void S::m3() { } // expected-warning{{unused}} |