summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-08-13 18:42:29 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-08-13 18:42:29 +0000
commit540bc01f500e353d3233edb799b1b5d868633c48 (patch)
tree1d84c58136922739a7fe41e2443c10da8e781630 /clang
parent35672e78523162ab292962ce5aec3f512ee5cf8a (diff)
downloadbcm5719-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.h4
-rw-r--r--clang/lib/Sema/Sema.cpp36
-rw-r--r--clang/lib/Sema/SemaDecl.cpp50
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp4
-rw-r--r--clang/test/Sema/warn-unused-function.c9
-rw-r--r--clang/test/SemaCXX/warn-unused-filescoped.cpp27
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}}
OpenPOWER on IntegriCloud